编写 java 卡片小程序的有效方法是什么?
What is the efficient way in writing a java card applet?
关于缺少垃圾收集器,我很困惑定义字段和变量的最佳方式是什么?
我们知道,在Java Card技术中,那些用new
关键字分配的对象,在超出作用域时变得不可访问,但是它们占用的存储空间space将永远不会被回收。
现在,假设我想在接收每个 APDU 命令时发送 'Hello'。
这些实现之间有什么区别(内存和 CPU 消耗)?哪个最好,为什么?
1-
public class SimpleApp extends Applet {
byte[] hello = { (byte) 'H', (byte) 'e', (byte) 'l', (byte) 'l', (byte) 'o' };;
private SimpleApp() {
}
public static void install(byte bArray[], short bOffset, byte bLength)
throws ISOException {
new SimpleApp().register();
}
public void process(APDU arg0) throws ISOException {
byte[] buffer = arg0.getBuffer();
Util.arrayCopyNonAtomic(hello, (short) 0, buffer, (short) 0, (short) 5);
arg0.setOutgoingAndSend((short) 0, (short) 5);
}
}
2-
public class SimpleApp extends Applet {
static byte[] hello = { (byte) 'H', (byte) 'e', (byte) 'l', (byte) 'l', (byte) 'o' };;
private SimpleApp() {
}
public static void install(byte bArray[], short bOffset, byte bLength)
throws ISOException {
new SimpleApp().register();
}
public void process(APDU arg0) throws ISOException {
byte[] buffer = arg0.getBuffer();
Util.arrayCopyNonAtomic(hello, (short) 0, buffer, (short) 0, (short) 5);
arg0.setOutgoingAndSend((short) 0, (short) 5);
}
}
3-
public class SimpleApp extends Applet {
byte[] hello = { (byte) 'H', (byte) 'e', (byte) 'l', (byte) 'l', (byte) 'o' };;
private SimpleApp() {
}
public static void install(byte bArray[], short bOffset, byte bLength)
throws ISOException {
new SimpleApp().register();
}
public void process(APDU arg0) throws ISOException {
byte[] buffer = new byte[255];
buffer = arg0.getBuffer();
Util.arrayCopyNonAtomic(hello, (short) 0, buffer, (short) 0, (short) 5);
arg0.setOutgoingAndSend((short) 0, (short) 5);
}
}
4-
public class SimpleApp extends Applet {
static byte[] hello = { (byte) 'H', (byte) 'e', (byte) 'l', (byte) 'l', (byte) 'o' };;
byte[] buffer;
private SimpleApp() {
}
public static void install(byte bArray[], short bOffset, byte bLength)
throws ISOException {
new SimpleApp().register();
}
public void process(APDU arg0) throws ISOException {
buffer = arg0.getBuffer();
Util.arrayCopyNonAtomic(hello, (short) 0, buffer, (short) 0, (short) 5);
arg0.setOutgoingAndSend((short) 0, (short) 5);
}
}
5-
public class SimpleApp extends Applet {
static byte[] hello = { (byte) 'H', (byte) 'e', (byte) 'l', (byte) 'l', (byte) 'o' };;
static byte[] buffer;
private SimpleApp() {
}
public static void install(byte bArray[], short bOffset, byte bLength)
throws ISOException {
new SimpleApp().register();
}
public void process(APDU arg0) throws ISOException {
buffer = arg0.getBuffer();
Util.arrayCopyNonAtomic(hello, (short) 0, buffer, (short) 0, (short) 5);
arg0.setOutgoingAndSend((short) 0, (short) 5);
}
}
版本 1:
缓冲区作为实例变量存储在 EEPROM 中。这个可以。
版本 2:
缓冲区作为 class 变量存储在 EEPROM 中。这个可以。
但是,这里提到的静态字段可能存在一些安全问题 https://community.oracle.com/thread/1752580:
The JCRE creates a context shared by any instance of application that
belong to a package. They are separated by the firewall so any
application in another context cannot access. Static variables and
methods don't belong to instance, belong to the class itself so the
are out of the scope of the firewall and are accesibles by any
application in the smartcard. So we're dealing with a serious security
risk.
或此处:http://pfa12.free.fr/doc_java/javacard_specifications/specs/jcre/html/JCRESpec06firewall.html(第 6.1.6 章)
Instances of classes—objects—are owned by contexts; classes themselves
are not. There is no runtime context check that can be performed when
a class static field is accessed. Neither is there a context switch
when a static method is invoked. (Similarly, invokespecial causes no
context switch.)
Public static fields and public static methods are accessible from any
context: static methods execute in the same context as their caller.
Objects referenced in static fields are just regular objects. They are
owned by whomever created them and standard firewall access rules
apply. If it is necessary to share them across multiple contexts, then
these objects need to be Shareable Interface Objects (SIOs).
上面的文字并不意味着您完全不能使用静态字段和方法。您只需要仔细考虑即可。另一件事是对实例的静态引用可能很危险:它们可能会导致一种情况,当您的小程序无法删除时,如下所述:http://askra.de/software/jcdocs/app-notes-2.2.2/garbagecoll.html:
Deleting an applet means that the applet and all of its child objects
are deleted. Applet deletion fails if any of the following conditions
exist:
Any object owned by the applet instance is referenced by an object owned by another applet instance on the card.
Any object owned by the applet instance is referenced from a static field in any package on the card.
版本 3:
每个 APDU 在 EEPROM 中创建一个新缓冲区。一个非常糟糕的主意。如果没有垃圾收集器,您的小程序将很快因为缺少 EEPROM 而失败。使用垃圾收集器,您的小程序将非常慢。仅在您的小程序构造函数中或在某些初始 "Store Data" 阶段分配新实例。
版本 4,5:
这根本行不通。它会导致异常。您不能将 APDU 缓冲区引用存储在 class 或实例变量中:
References to the APDU buffer byte array cannot be stored in class
variables or instance variables or array components. See Runtime
Environment Specification for the Java Card Platform, section 6.2.2
for details.
关于缺少垃圾收集器,我很困惑定义字段和变量的最佳方式是什么?
我们知道,在Java Card技术中,那些用new
关键字分配的对象,在超出作用域时变得不可访问,但是它们占用的存储空间space将永远不会被回收。
现在,假设我想在接收每个 APDU 命令时发送 'Hello'。
这些实现之间有什么区别(内存和 CPU 消耗)?哪个最好,为什么?
1-
public class SimpleApp extends Applet {
byte[] hello = { (byte) 'H', (byte) 'e', (byte) 'l', (byte) 'l', (byte) 'o' };;
private SimpleApp() {
}
public static void install(byte bArray[], short bOffset, byte bLength)
throws ISOException {
new SimpleApp().register();
}
public void process(APDU arg0) throws ISOException {
byte[] buffer = arg0.getBuffer();
Util.arrayCopyNonAtomic(hello, (short) 0, buffer, (short) 0, (short) 5);
arg0.setOutgoingAndSend((short) 0, (short) 5);
}
}
2-
public class SimpleApp extends Applet {
static byte[] hello = { (byte) 'H', (byte) 'e', (byte) 'l', (byte) 'l', (byte) 'o' };;
private SimpleApp() {
}
public static void install(byte bArray[], short bOffset, byte bLength)
throws ISOException {
new SimpleApp().register();
}
public void process(APDU arg0) throws ISOException {
byte[] buffer = arg0.getBuffer();
Util.arrayCopyNonAtomic(hello, (short) 0, buffer, (short) 0, (short) 5);
arg0.setOutgoingAndSend((short) 0, (short) 5);
}
}
3-
public class SimpleApp extends Applet {
byte[] hello = { (byte) 'H', (byte) 'e', (byte) 'l', (byte) 'l', (byte) 'o' };;
private SimpleApp() {
}
public static void install(byte bArray[], short bOffset, byte bLength)
throws ISOException {
new SimpleApp().register();
}
public void process(APDU arg0) throws ISOException {
byte[] buffer = new byte[255];
buffer = arg0.getBuffer();
Util.arrayCopyNonAtomic(hello, (short) 0, buffer, (short) 0, (short) 5);
arg0.setOutgoingAndSend((short) 0, (short) 5);
}
}
4-
public class SimpleApp extends Applet {
static byte[] hello = { (byte) 'H', (byte) 'e', (byte) 'l', (byte) 'l', (byte) 'o' };;
byte[] buffer;
private SimpleApp() {
}
public static void install(byte bArray[], short bOffset, byte bLength)
throws ISOException {
new SimpleApp().register();
}
public void process(APDU arg0) throws ISOException {
buffer = arg0.getBuffer();
Util.arrayCopyNonAtomic(hello, (short) 0, buffer, (short) 0, (short) 5);
arg0.setOutgoingAndSend((short) 0, (short) 5);
}
}
5-
public class SimpleApp extends Applet {
static byte[] hello = { (byte) 'H', (byte) 'e', (byte) 'l', (byte) 'l', (byte) 'o' };;
static byte[] buffer;
private SimpleApp() {
}
public static void install(byte bArray[], short bOffset, byte bLength)
throws ISOException {
new SimpleApp().register();
}
public void process(APDU arg0) throws ISOException {
buffer = arg0.getBuffer();
Util.arrayCopyNonAtomic(hello, (short) 0, buffer, (short) 0, (short) 5);
arg0.setOutgoingAndSend((short) 0, (short) 5);
}
}
版本 1: 缓冲区作为实例变量存储在 EEPROM 中。这个可以。
版本 2: 缓冲区作为 class 变量存储在 EEPROM 中。这个可以。
但是,这里提到的静态字段可能存在一些安全问题 https://community.oracle.com/thread/1752580:
The JCRE creates a context shared by any instance of application that belong to a package. They are separated by the firewall so any application in another context cannot access. Static variables and methods don't belong to instance, belong to the class itself so the are out of the scope of the firewall and are accesibles by any application in the smartcard. So we're dealing with a serious security risk.
或此处:http://pfa12.free.fr/doc_java/javacard_specifications/specs/jcre/html/JCRESpec06firewall.html(第 6.1.6 章)
Instances of classes—objects—are owned by contexts; classes themselves are not. There is no runtime context check that can be performed when a class static field is accessed. Neither is there a context switch when a static method is invoked. (Similarly, invokespecial causes no context switch.)
Public static fields and public static methods are accessible from any context: static methods execute in the same context as their caller.
Objects referenced in static fields are just regular objects. They are owned by whomever created them and standard firewall access rules apply. If it is necessary to share them across multiple contexts, then these objects need to be Shareable Interface Objects (SIOs).
上面的文字并不意味着您完全不能使用静态字段和方法。您只需要仔细考虑即可。另一件事是对实例的静态引用可能很危险:它们可能会导致一种情况,当您的小程序无法删除时,如下所述:http://askra.de/software/jcdocs/app-notes-2.2.2/garbagecoll.html:
Deleting an applet means that the applet and all of its child objects are deleted. Applet deletion fails if any of the following conditions exist:
Any object owned by the applet instance is referenced by an object owned by another applet instance on the card.
Any object owned by the applet instance is referenced from a static field in any package on the card.
版本 3: 每个 APDU 在 EEPROM 中创建一个新缓冲区。一个非常糟糕的主意。如果没有垃圾收集器,您的小程序将很快因为缺少 EEPROM 而失败。使用垃圾收集器,您的小程序将非常慢。仅在您的小程序构造函数中或在某些初始 "Store Data" 阶段分配新实例。
版本 4,5: 这根本行不通。它会导致异常。您不能将 APDU 缓冲区引用存储在 class 或实例变量中:
References to the APDU buffer byte array cannot be stored in class variables or instance variables or array components. See Runtime Environment Specification for the Java Card Platform, section 6.2.2 for details.