作者归档:softsim

在JNI中避免使用全局静态变量

Java 可以加载一个类的多个实例(因为例如有多个类加载器classloader),并且静态变量将在所有实例之间共享。 不幸的是,清理调用也是如此,如果您的类的一个实例被销毁而另一个仍在使用中,则会导致不一致。

在这些情形,使用 native class constructor / finalizer 并分配/取消 内存资源 会更明智。

你不能假设 Java会以单线程模式调用natvie函数。


大多数代码只需要在一个线程里运行,这样,就不需要锁定机制。
但是,不能因为只有一个线程, 就直接用 static mut, 并将 对它的访问 wrap到unsafe代码块里。
这样可能会出现严重的内存问题。
举个例子, 从全局变量中不安全地借用可能会同时给我们多个可变引用。 然后我们可以使用其中一个来迭代一个向量,
但另一个却从同一个向量中删除值。 然后迭代器可能会超出有效的内存边界,这种潜在崩溃, 是安全的 Rust 可以防止的。

Rust标准库, 提供了一种“全局”存储值的方法,可在单个线程中安全访问。这就是 thread local.
在多线程的情况下,每个线程都会获得变量的独立副本。

thread local优缺点

坏处就是, 该静态对象,对你的程序产生的其他线程,并不可见。
好处就是,与真正的全局状态不同,它是完全安全的,无痛使用— 真正的全局状态,在任何语言中,都是一个巨大的痛苦。

使用thread local不是最简单的方案,但是它允许执行任意的初始化代码, 这些初始化代码
只有在第1次 访问该变量的值时,才会执行。


use lazy_static::lazy_static;
use std::collections::HashMap;

lazy_static! {
    static ref PRIVILEGES: HashMap<&'static str, Vec<&'static str>> = {
        let mut map = HashMap::new();
        map.insert("James", vec!["user", "admin"]);
        map.insert("Jim", vec!["user"]);
        map
    };
}

fn show_access(name: &str) {
    let access = PRIVILEGES.get(name);
    println!("{}: {:?}", name, access);
}

fn main() {
    let access = PRIVILEGES.get("James");
    println!("James: {:?}", access);

    show_access("Jim");
}

lazy_static! {
    static ref USER_TOKEN_HASHMAP: Mutex> = Mutex::new(HashMap::new());
}

fn func() {
    let mut _map = USER_TOKEN_HASHMAP.lock().unwrap();
    let user_email = String::from("aaa");
    let user_password = String::from("bbb");
    _map.insert(user_email, user_password);
}

必须用Mutex

参考资料
https://www.sitepoint.com/rust-global-variables/

BluetoothAdapter setName

1. 蓝牙必须启用,setName()才能工作. 如果蓝牙当前状态是关闭的,调用setName是无效的。
2. 启用蓝牙需要时间。也就是说,你不能在调用 enable()之后马上再调用setName()
3. 名字需要一定时间生效。 也就是说,你不能在setName()之后,马上调用getName()就能得到新设置的名字

为什么rust编译出的可执行文件体积那么大

因为Rust用静态链接(static linking)来编译可执行文件。

也就是说,所有依赖的库,都会编译进去。当然也包含了Rus runtime

可以添加

-C prefer-dynamic

命令行参数, 来让rust编译器是用动态链接。

如果用cargo,这个选项也要传给rustc

cargo rustc --debug  -- -C prefer-dynamic
或者
cargo rustc --release -- -C prefer-dynamic

进一步,在Cargo.toml中配置,也可以减少一些体积

[profile.release]
opt-level = 'z'     # Optimize for size.
lto = true          # Enable Link Time Optimization
codegen-units = 1   # Reduce number of codegen units to increase optimizations.
panic = 'abort'     # Abort on panic
strip = true        # Strip symbols from binary*

https://lifthrasiir.github.io/rustlog/why-is-a-rust-executable-large.html
https://stackoverflow.com/questions/29008127/why-are-rust-executables-so-huge

F2 Status

返回当前目录或者当前应用的相关信息

按照应用规范,这个命令可能用来指出 在UICC的应用的初始化过程已经成功执行,或者终止过程即将执行。

注意:这个之事,也可能用来同步终端和UICC上的应用。

P1 = 0 没有额外的指示,仅仅想知道卡还在不在

P1 = 1 当前应用 已经在终端被初始化(也就是准备好让这张卡入网)

P1= 2 终端准备 关闭uicc上的应用

p2=0 Response parameters and data are identical to the response parameters and data of the SELECT command

p2 =1 The DF name TLV-object of the currently selected application is returned

p2 =c 不要返回额外的数据,我就是看看卡还在不在

6FAD

此EF包含有关操作模式(按照usim类型而不同的模式)的信息。

正常模式(用户登录3GPP网络)

型号批准(在型号批准过程中,允许ME的特定的使用)

基站小区测试(在某个小区在商用之前,进行测试)

制造商特定的用途(允许ME制造商执行专有的自动测试,例如维护阶段)

此文件的内容至少为4个字节,其中前4个字节的含义

1字节 UE operation mode
00 = 正常模式
80 = 类型批准操作
01 = 正常模式+特定设施
81 = 型号批准操作 + 特定
02 = 维护(离线)
04 = 小区测试操作

2-3字节 Additional information
UE操作模式的额外信息
4字节 length of MNC in the IMSI

如果 service n°130 is “available”, 那么这个字节为0
否则,应该为 2 或者 3 表示 MNC的长度为2 或者 3

130号服务是 Support for SUPI of type NSI or GLI or GCI

如130号服务可用,那么 EF_IMSI (6F07)就不应该存在

proactive UICC command通用元素

1命令编号

命令编号是为了满足未来可能出现的多个正在进行的命令(UICC在收到对正在进行的命令的响应之前,发出进一步的命令)。在toolkit规范的这个阶段,还没有对这种多个命令的含义进行详细说明。

在卡会话期间,有主动UICC发出的每个命令都应该有自己的命令编号。编号可以为在01-FE之间的任何十六进制值。命令编号保存在 “命令详细信息”数据对象中.

UICC负责分配命令编号。终端应该记录每条命令的状态和命令编号,直到终端使用TERMINAL RESPONSE向UICC发出命令的结果。

此后,终端可能会擦除有关此命令的所有内部记录。此命令编号可以由UICC分配给新的命令。

UICC Maximum Power Consumption

跟EF_DIR, EF_ICCID, EF_PL, EF_ARR一样, EF_UMPC也是一个应用无关的文件

放在MF(3F00)下

很多卡上实际没有这个文件

虽然规范是要求这个文件 必须存在

电信卡有这个文件

FCP: 62198205422100093283022F088A01058B032F0605800201C28800

62 19

82 05 42(工作EF,线性固定,共享) 21 00 09(记录长度) 32 (记录个数)

83 02 2F08

8A 01 05 (生命周期:激活)

8B 03 2F0605

80 02 01 C2 (文件大小)

88 00 (无SFI)

3F00 2FE2 0000000001

3F00 7F20 6F20 000000

3F00 7F25 6F31 000001

3F00 7FF1 6F31 000001

3F00 7FF1 6F46 000001

看来这个文件被挪做他用了

rust拼接切片(concatenate two slices /join two slices as a new slice)

如果都是vector,可以用vector自带的append方法 或者 Extend trait 或者slice的concat方法

fn main() {
    let mut a = vec![1, 2, 3];
    let mut b = vec![4, 5, 6];

    a.append(&mut b);

    assert_eq!(a, [1, 2, 3, 4, 5, 6]);
    assert_eq!(b, []);
}
或者
fn main() {
    let mut a = vec![1, 2, 3];
    let b = vec![4, 5, 6];

    a.extend(b);
    assert_eq!(a, [1, 2, 3, 4, 5, 6]);
}
或者

fn main() {
    let mut a = vec![1, 2, 3];
    let b = vec![4, 5, 6];

    [a, b].concat()
    assert_eq!(a, [1, 2, 3, 4, 5, 6]);
}

用extend_from_slice

fn cat<T: Clone>(a: &[T], b: &[T]) -> Vec<T> {
let mut v = Vec::with_capacity(a.len() + b.len());
v.extend_from_slice(a);
v.extend_from_slice(b);
v
} 或者
fn join<T: Clone>(a: &[T], b: &[T]) -> Vec<T> { a.iter().cloned().chain(b.iter().cloned()).collect() }
或者 fn join<T: Clone>(a: &[T], b: &[T]) -> Vec<T> { let mut v = a.to_vec(); v.extend_from_slice(b); v }

rust得到变量的类型和占用空间的大小

两种写法
1. 直接打印

fn print_type_of<T>(_: &T) {
    println!( "{}", std::any::type_name::<T>()   );
}

或者
fn print_type_of<T>(_: T) {
    println!("{}", std::any::type_name::<T>());
}
上面那种,传 引用,  
下面这种,直接传值, 会转移所有权

2. 返回字符串

fn type_of<T>(_: T) -> &'static str {
std::any::type_name::<T>()
} 或者 fn type_of<T>(_: &T) -> &'static str { std::any::type_name::<T>() } 也是 转移所有权的区别 调用示范: println!("{}", type_of(&x));

3.其他方法 (新功能https://github.com/rust-lang/rust/issues/66359)

use std::any::type_name_of_val;
let x = 1;
println!("{}", type_name_of_val(&x));

4.基本类型:
1)整数:
u8, i8, u16, i16, u32, i32, u64, i64, u128, i128

2)浮点数:
f32, f64

3)逻辑数(布尔类型)
true, false

4)字符 (char)

let alphabet:char = 'A';
let emoji:char = '😁';

5)数组 array

6) 元组 tuple

5. 完整代码

fn type_of(_: &T) -> &'static str {
    std::any::type_name::()
}


fn main() {
    let buff = [0x21 as u8, 0x22, 0x23, 0x24];

    println!("{}", type_of(&buff));
}

运行结果:
[u8; 4]

6. 得到占用空间的大小

fn main() {
    fn size_of_val<T>(_: &T) -> usize {
        std::mem::size_of::<T>()
    }
    
    let arr = [0u8; 4];
    println!("size_of arr: {}", size_of_val(&arr));
}

7. 图示

Rust Container cheat sheet

rust的数组array向量vector切片slice字符串str

1. 数组 array
Rust 中的数组是固定长度的:一旦声明,它们的长度不能增长或缩小。

let a = [1, 2, 3, 4, 5];
let a: [i32; 5] = [1, 2, 3, 4, 5];
let a = [3; 5];
let a = [3, 3, 3, 3, 3];

当你想要在栈(stack)而不是在堆(heap)上为数据分配空间,或者是想要确保总是有固定数量的元素时,数组非常有用。
正是因为array存储在stack上,所以必须固定大小。

2.切片 slice
slice是没有所有权的,它引用集合中一段连续的元素序列,而不用引用整个集合。

let a = [1, 2, 3, 4, 5];
let slice = &a[1..3];

3.基础类型字符串 str

str 本质也是表示一段 u8 序列,只是附带了额外的要求:这些 u8 序列必须是合法的 utf-8 编码

str 类型,也称为字符串切片(string slice),是最基本的字符串类型。它通常以借用的形式出现, 它们是一些储存在别处的 UTF-8 编码字符串数据的引用。它也是字符串字面值(string literals)的类型,  也就是 &'static str

字符串字面值:


let s = "Hello, world!";

这里 s 的类型是 &str:它是一个指向二进制程序(binary executes)特定位置的 slice。这也就是为什么字符串字面值是不可变的;&str 是一个不可变引用。

&str 占用 16 个字节,除了 8 个字节代表其指向的第一个字节的地址之外,还有 8 个字节代表其所涵盖的字节长度(所以 &str 又被称为胖指针

4. 向量 vector

Vec 本质是一个指针,所以 Vec 变量是定长的,可以在Stack上存储;它指向Heap的一段具有相同类型的数据序列

5. String

String本质是Vec<u8>,  同str一样, 要求Heap中的u8序列是合法的utf编码

用代码查看类型

fn type_of<T>(_: T) -> &'static str {
     std::any::type_name::<T>()
}

fn main() {
    let x = 21;
    let y = 2.5;
    let strz = "abcd";
    let str_slice = &strz[1..3];
    
    let array_ref =  b"abcd";
    let array_slice = &array_ref[1..3];
    
    let arr = [0x61 as u8, 0x62, 0x63, 0x64];
    let arr_slice = &arr[1..3]; 

    println!("{}", type_of(&y));
    println!("{}", type_of(x));
    println!("str= {}", type_of(strz));
    println!("str slice= {}", type_of(str_slice));
    println!("array ref ={}", type_of(array_ref));
    println!("array slice= {}", type_of(array_slice)); 
    println!("String={}", type_of(String::from(strz)));
    println!("array={}", type_of(arr)); 
    println!("arr slice={}", type_of(arr_slice)); 
    println!("vec={}", type_of(vec![0x61 as u8, 0x62, 0x63, 0x64]));
    println!("{}", type_of(main));
    println!("{}", type_of(type_of::<u8>));

}


运行结果
&f64
i32
str= &str
str slice= &str
array ref =&[u8; 4]
array slice= &[u8]
String=alloc::string::String
array=[u8; 4]
arr slice=&[u8]
vec=alloc::vec::Vec<u8>
vexample::main
vexample::type_of<u8>