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>

从Rust中调用C代码

unsafe关键字

0. 新建一个InvokeC的工程

cargo new  InvokeC

1.编辑 src/main.c

extern "C" {
    fn doubler(x: i32) -> i32;
}

fn main() {
    println!("[rust] start");
    unsafe { 
        println!("{}", doubler(6));
    }
}

2. 编辑 src/hello.c

#include stdio.h

int doubler(int x) {
    return x * 2;
}

3.编译C代码

$ cc -c src/hello.c
$ cc -shared hello.o -o libnum.so

4.用rustc 编译代码,并动态链接到 libnum

rustc -l num -L . src/main.rs

5. 运行

LD_LIBRARY_PATH=.  ./main

如果不设置 LD_LIBRARY_PATH 变量, 将会找不到 libnu.so 动态库

6. 也考虑生成静态库

$  ar rcs libnum.a   hello.o

7.链接到静态库

rustc -l static=num -L. src/main.rs  

8.直接运行

./main

9. 如何不用rustc编译, 而是用cargo build或者cargo run
在项目的根目录下,建立一个 build.rs 文件

fn main() {
    println!("cargo:rustc-link-search=.");
    println!("cargo:rustc-link-lib=static=num");
}

就可以了
如果是动态库

    println!("cargo:rustc-link-search=all=src");      //  类似"rustc -L src ..." 
    println!("cargo:rustc-link-lib=dylib=num"); // 类似"rustc -l num"

或者在源代码中 指定链接选项
main.c中

#[link(name = "num", kind = "static")]
extern "C" {
    fn doubler(x: i32) -> i32;
}
...

就可以把 build.rs中

println!("cargo:rustc-link-lib=static=num");

这一行去掉

最后,如果连编译C代码都不想手动去做,可以用一个 cc的库, 在Cargo.toml中添加

[build-dependencies]
cc = "1.0"

注意:是 build-dependencies 而不是 dependencies

然后,将 build.rs改为

fn main() {
    cc::Build::new()
        .file("src/hello.c")
        .compile("libnum.a");
}

或者

fn main() {
    cc::Build::new()
        .file("src/hello.c")
        .compile("anything");
}

adb push照片并用广播更新相册媒体库

上传到 /sdcard/Pictures/up 目录

adb push   front.jpg   /sdcard/Pictures/up

广播通知

adb shell am broadcast -a android.intent.action.MEDIA_SCANNER_SCAN_FILE   -d file:///storage/emulated/0/Pictures/up/front.jpg
或者
adb shell am broadcast -a android.intent.action.MEDIA_MOUNTED             -d file:///storage/emulated/0/Pictures/up

Linux设备上的永久或半永久ID

用来唯一地识别机器
1. 网卡MAC
MAC地址本来是永久地保存在 网卡的EEPROM里的,通过驱动程序读取出来,该地址放在 Link层用来识别自身。但是驱动程序可以用
自己配置的MAC地址,而不是从网卡芯片读取的
缺点:
1) 有些机器上没有网卡
2) 通ifconfig命令 可以修改地址
命令:

ifconfig eth0
ip link show eth0
cat /sys/class/net/eth0/address 

2. 存储芯片ID
/sys/block/mmcblk2/device/cid

Name Field Linux attribute* Description
Manufacturer ID MID manfid Assigned by SD-3C, LLC.
OEM/Application ID OID oemid Identifies the card OEM and/or the card contents. Assigned by SD-3C, LLC.
Product Name PNM name 5 characters long (ASCII)
Product Revision PRV hwrev, fwrev Two binary coded decimal (BCD) digits. Each is four bits. The PRV is in the form x.y. The PRV can also be found by using the hwrev and fwrev, where x=hwrev and y=fwrev
Serial Number PSN serial This 32 bit field is intended to be read as an unsigned integer
Manufacture Date Code MDT date Manufacture date is stored in the form yym (offset from 2000)
CRC7 checksum CRC 7 bit code used for checking errors in the card register

这个比较难修改,除非修改内核

3. 存储分区ID
文件系统分区时生成的ID, 可以通过分区程序等进行修改

blkid
fdisk -l /dev/mmcblk2

PTUUID
PARTUUID
UUID

4. 安装系统时生成的machine-id
/var/lib/dbus/machine-id
/etc/machine-id
缺点: 非常容易被root权限用户修改

5. 内核随机UUID

/proc/sys/kernel/random/uuid
/proc/sys/kernel/random/boot_id

每次重启会变

6. USB设备的序列号
存在USB设备的EEPROM中
/sys/bus/usb/devices/*/serial

cat  sys/bus/usb/devices/1-4.3/serial

缺点:
1) USB设备是可以热插拔的
2) 有些设备没有序列号,另外有些设备的序列号是伪造的,同一批设备都是一样的

Copy trait和Clone trait

Copy trait表示可以通过memcpy安全地复制的值, 想 赋值和 通过值来传递参数 这些操作总是通过memcpy来进行。
如果,实现了Copy trait的值,如果进行赋值 和 通过值传参, 不会 移动 所有权。

let x: u8 = 123;
let y = x;
// x 复制了一份到y,  x 没有移动,还可以用
println!("x={}, y={}", x, y);

// Vec<u8>  实现 Clone, 但没有实现Copy
let v: Vec<u8>  = vec![1, 2, 3];

let w = v;  // 所以,赋值操作, 会"移动" 值到 w,  现在v已经没了

let w = v.clone();

每一个实现了Copy trait的类型,都会要求实现Clone.
然而,它们的要求是不一样的。
对于你自己定义的类型, .clone()函数的实现,可以用你选择的任意方法,但是
隐式的copy(比如赋值操作),总是会触发一个memcpy, 而不是调用clone(&self)的实现

Copy是隐式的,不能被重新实现(用的是memcpy)
Clone是显式调用,可能实现的代价很昂贵,可以用任意的方式来实现
通常有Copy trait的类型,都是简单的基本类型。

只有完全存在于stack中的类型(所有的内容都在stack上,而不是有一部分内容放在heap, 而其引用放在stack),才能实现Copy.
实现Copy意味着 该类型的值,能够 按照它的stack 上的表示,进行按位复制。
赋值操作,不会让之前的所有者失效,而是会创建一个克隆。
String类型将其内容存储在Heap上,所以她不是Copy

rust声明一个结构体的数组并初始化

rust要求每个元素都必须被初始化

struct Point {
    x: u32,
    y: u32,
}
let p: [Point; 2] = [Point { x: 1, y: 2 }, Point { x: 2, y: 3 }];

用不安全的代码 MaybeUninit

use std::{mem::MaybeUninit, ptr};

let p = unsafe {
        let mut p = MaybeUninit::<[Point; 2]>::uninit();
        let h = p.as_mut_ptr() as *mut Point;
        ptr::write(h.offset(0), Point { x: 1, y: 2 });
        ptr::write(h.offset(1), Point { x: 2, y: 3 });

        p.assume_init()
};

用None初始化

let mut p: [Option<Point>; 2] = [None, None];

p[0] = Some(Point { x: 1, y: 2 });
p[1] = Some(Point { x: 2, y: 3 });

用ArrayVec

    let p = {
        let mut p = ArrayVec::<[Point; 2]>::new();

        p.insert(0, Point { x: 1, y: 2 });
        p.insert(1, Point { x: 2, y: 3 });

        p.into_inner()
    };

用Vec来代替数组

let mut test_vec = Vec::with_capacity(20);
for _ in 0..2 {
    vec.push(Point { x: 1, y: 2 });
}

用Clone trait来初始化, 这仅仅对实现了Copy trait 的基本类型有用

#[derive(Debug)]
struct Point {
    a: i32,
    b: u32,
}

impl Copy for Point {}

impl Clone for Point {
    fn clone(&self) -> Point {
        Point{a: self.a, b: self.b}
    }
}

impl Point {
    fn new() -> Point {
        Point {a: 1, b: 2}
    }
}

fn main() {
    let test_var = Point::new();

    let test_array = [Point::new(); 4];
    println!("test_var: {:#?}", test_var);
    println!("test_array: {:#?}", test_array);
}