比较python和rust中的zip-map函数

先看python

a = [1,2,3]
b = [4,5,6]
c = [7,8,9,0]
list(zip(a,b))
list(zip(a,c))

结果为

[(1, 4), (2, 5), (3, 6)]
[(1, 7), (2, 8), (3, 9)]

再看rust

let a = [1, 2, 3];
let b = [4, 5, 6];
	
let d = a.iter().zip(b.iter());
	
for z in d {
    println!("{:?}", z);
}

结果

(1, 4)
(2, 5)
(3, 6)

功能都是类似的

再看看map

map(lambda x: x ** 2, [1, 2, 3, 4, 5])
map(lambda x, y: x + y, [1, 3, 5, 7, 9], [2, 4, 6, 8, 10])

rust 3个迭代

let itr1 = [100, 200, 300, 400, 500, 600];
let itr2 = [10 , 20, 30, 40, 50 ,60];
let itr3 = [1, 2, 3, 4 ,5 , 6];
	
let iter = itr1.iter()
		.zip( itr2.iter())
		.zip( itr3.iter())
		.map(|((x, y), z)| (x, y, z));

for (itr1, itr2, itr3) in iter {
	println!("{} {} {}", itr1, itr2, itr3);
}

rust vector创建与修改

1.可以用rust核心库自带的new函数 (在prelude中,无需import)

let v:  Vec<i32> = Vec::new();

2.用vec!宏创建

let v = vec![1, 2, 3];
或者
let v = vec![0xFF; 3];

3.更新

v.push(5);
v.push(6);
v.push(7);
v.push(8);

4. 从 slice中复制

let b &[u8] = b"softs.im";
v.copy_from_slice(b);

copy_from_slice(&mut self, src: &[T])
速度很快,如果类型实现了Copy trait, 就会用memcpy复制元素。
如果没有实现,就是用 cloent_from_slice
此函数 要求src和self的长度一样

5. 替换元素

    
	let mut v: Vec = vec![0xFF; 8];

	let b: &[u8] = b"softs.im";
	v.copy_from_slice(b);

        println!("v = {:?}", v);

6. 对于Vec<u8> 写入byte array, 是追加,不是覆盖。容量会自动增加

 
write(&mut self, buf: &[u8]) -> Result<usize> 
write_all(&mut self, buf: &[u8]) --> Result<()>

7. 对于Vec<u8> , 还可以从String来创建

from(string: String) -> Vec<u8, Global>
from(s: &str) -> Vec<u8, Global>

8. 填充

let mut buf = vec![0; 10];
buf.fill(1);
assert_eq!(buf, vec![1; 10]);

9. 用map zip进行复制

let a = [1, 2, 3, 4, 5];
let slice = &a[1..4];
let mut x: Vec<u8> = vec![0; 3];
println!("X at startup: {:?}", x);    
slice.iter().zip(x.iter_mut()).map(|(&t, p)| *p = t).count();
println!("X copied from vec: {:?}", x);

不用map, 可写成

    for (&t, p) in slice.iter().zip(x.iter_mut()) {
        *p = t;
    }

10. 用 try_into()

11. 部分复制: 把buffer复制到memory偏移地址STARTING_PROGRAM_ADDRESS处

用枚举, 可以得到index
for (index, byte) in buffer.iter().enumerate() {
    memory[STARTING_PROGRAM_ADDRESS + index] = *byte;
}
用copy_from_slice
memory[STARTING_PROGRAM_ADDRESS..(STARTING_PROGRAM_ADDRESS + buffer.len())]
    .copy_from_slice(buffer.as_slice());
或
memory[STARTING_PROGRAM_ADDRESS..][..buffer.len()]
    .copy_from_slice(&buffer);

用zip
for (src, dst) in buffer.iter().zip(memory.iter_mut().skip(STARTING_PROGRAM_ADDRESS)) {
    *dst = *src;
}
或
for (src, dst) in buffer.iter().zip(&mut memory[STARTING_PROGRAM_ADDRESS..]){
    *dst = *src;
}

FDN-BDN和呼叫控制

如果UST中的2号 和/或 89号服务存在,那么 EF_FDN文件就应该存在
2–Fixed Dialling Numbers (FDN)
89–eCall Data (紧急呼叫)
———
这个文件含有 固定拨打号码 和/或 补充服务控制字符串
另外,,还有 关联网络/承载者能力 识别符, 扩展记录识别符
它也可以包含一个关联的 alhpha-tagging
如果这个文件存在USIM中,那么 Ef_EST 文件也应该存在
———
文件标识符:6F3B

对于项目的编码,可以参考 EF_ADN 和 EF EXT2

1字节: 号码长度
2字节: TON和NPI,表示国际还是本地号码
3字节-12字节: 号码
13字节:Capability/Configuration2 Record Identifier
14字节:Extension2 Record Identifier

用于识别 EF CCP2中记录,如果设置为FF,表示不需要关联CCP2的记录
EF EXT2, 也可以设置为FF
—–
启用FDN后,默认情况下,如果要拨打目标地址不在FDN中,那么CS承载的通话, IMS通信,以及SMS都是不允许的

—————–
对于短信相关的FDN过程,请参考 TS 131.111 和 TS 122.101

———–
EF_EXT2
6F4B
含有FDN的扩展数据
——–
EF_CCP2
参考 TS 124.008
里面包含 Information Element Identity (IEI)
————-
EF FDNURI (Fixed Dialling Numbers URI)
6FED
如果2号和99号服务存在,那么这个文件就应该存在
编码参考 TS 131.103 中的 EF_IMPU的 URI TLV数据
—————————-
USIM初始化过程中,
如果SIM卡上的FDN启用,但ME不支持FDN, ME应该允许紧急呼叫,但不应该允许任何 主叫语音和主叫短信。
如果SIM卡上的BDN启用, ME不支持呼叫控制, ME就应该允许紧急呼叫,但不应该允许 主叫语音。
————————-
如果SIM卡的FDN启用, ME在语音呼叫前,应只允许 固定的号码(在 TS 122.101里有描述)
为了确定FDN功能的状态, ME应该检查EF_UST和EF_EST的FDN标志都是激活的(服务激活且可用)。
其他情况, FDN是关闭的。
FDN激活,可通过 激活EST的FDN服务标志(它会自动打开UST的FDN标志)
FDN关闭, 也可以通过 关闭EST的FDN(只要一个标识是关闭的,这个功能就是无效的)

———-
ICE TS 122.030
————–
eCall相关过程
UST需要打开 89 (eCall Data)或者 112号服务(eCall Data over IMS), eCall功能才可用。
eCall提供两个号码或者URI, 一个测试号码/URI, 一个重配置 号码/URI
取决于eCall的类型, EF FDN or EF SDN or EF FDNURI or EF SDNUR 等文件用来提供eCall功能
——————-
eCall Only
要求:FDN启用,89号服务可用
如果eCall Only被支持,那么EF_FDN应该只有两个条目,一个条目含有测试号码,第二个条目含有eCall重新配置号码
这些号码用于通过CS来执行eCall. 如果服务 112 或者 99 不可用,那么 就会通过IMS 紧急呼叫服务来执行eCall.

FDN启用, 99(URI support by UICC) 和112服务可用,ME应该读取 EF_FDNURI 来决定 FDN号码
——————
SM-over-IP
要求: 12 和 91 服务可用
服务12: Short Message Service Parameters (SMSP)
服务91: ‘Support for SM-over-IP’

ME会执行读取 EF_PSISMSC

————–

IP短信

IP短信是让UE能通过IMS网络发送传统短信。
短信的结构定义在 TS 123.040
IP短信功能定于在 TS 123.204

为了保证 互操作, SM-over-IP发送者,接收者 和 IP-SM-GW网关 应该支持 封装RPDU(定义在TS 124.011的7.3节)
应该用 “application/vnd.3gpp.sms” 来实现这个封装。


提交一条短信
发送着应该发送一条 SIP MESSAGE请求:
a) Request-URI(含有SC的PSI)
注意:SC的PSI应该是 SIP URI或者tel URI (这取决与运行商的策略).
PSI应该用下面的方法取得(以优先级排序):
1) 由用户提供
2) 如果使用的是 UICC, 那么:
如果存在ISIM, 应该 从ISIM ADF下的DF_telecom目录的 EF_PSISMS文件中获取(请参考 TS 131.103)
如果不存在ISIM, 应该从USIM ADF下的DF_telecom目录的EF_PSISMSC (请参考 TS 131.102)
如果前面两个文件都不存在,应该从 EF SMSP文件中的TS-Service-Centre-Address获取,应该是一个 E.164 number
通过它来构造 tel URI或者SIP URI(“user=phone”)
3) 如果不是用的UICC, 而是老的SIM卡。那么只能按照 TS 51.011规范,在EF_SMSP中获取TS-Service Centre Address

b) From头部应该包含 发送者的 public user identity
c) To 头部应该包含 发送者的SC的PSI


SM-over-IP
要求: 12 和 91 服务可用
服务12: Short Message Service Parameters (SMSP)
服务91: ‘Support for SM-over-IP’
ME会执行读取 EF_PSISMSC

实际情况是 , 没有91号服务,只要开启 VoLTE, ME就会通过IP发送短信

sim卡proactive命令的结果

一旦终端(terminal)完成了对UICC主动命令的尝试,那么就应该通知UICC,命令的执行是成功还是失败。
终端用terminal response命令来完成这个通知。
一般有三种结果:
1. 命令成功执行
2. 临时失败。UICC可以再试
3. 永久失败。不应再试,除非重启

成功的结果, 有下面几种情形:
1. 成功了,没有任何问题。
….
6. 命令执行,但被call control修改。
主动命令的请求类型,被call control修改了,且call control要求的行为被成功执行了
这通常是 UICC用SET UP CALL主动命令来建立一个呼叫, UICC又支持呼叫控制, 终端就用ENVELOPE(call control)来交给UICC裁决,裁决的结果
是对 呼叫参数进行修改,修改后回应给终端, 终端根据回应结果,成功建立了呼叫。

永久失败:

同call control 交互,永久问题。 终端发送,用来指出:
1) uicc的call control规则 不允许 主动命令要求的呼叫行为
或者
2)uicc的call control规则 修改了 主动命令中的请求类型,但 终端 执行 uicc修改后的行为时遇到了一个永久性问题

ETSI TS 102 223 CAT 和 ETSI TS 131 111 USAT的Profile Download指令

Profile Download
提供一种机制, 让ME告诉UICC自己有什么能力
在UICC初始化过程(在 ETSI TS 131 101 定义) 中,该指令 由ME发送给UICC.
通过AT命令访问USAT的TE设备连接或者断开时,ME也会发送profile download命令给UICC

如果UICC在UST服务标中表明自己支持“在UICC激活后额外的Terminal Profile”, 那么ME应该按照 ETSI TS 102 223中规定的处理profile download

第1个字节
bit8 — 呼叫控制
bit7 — 在呼叫控制中支持 USSD 字符串数据对象(USSD string data object  support in Call Control by USIM)
bit6 — Timer expiration
bit5 —- SMS-PP 数据下载
bit4 — 菜单选择
bit3 — 小区广播数据下载
bit2 — SMS-PP 数据下载
bit1 — Profile download

第2个字节
bit8 — 显示文字
bit7 — UCS2显示支持
bit6 — UCS2 菜单条目支持
bit5 —- 呼叫控制 Call Control by USIM
bit4 — 发送短信控制 MO short message control by USIM
bit3 — 呼叫控制
bit2 — 呼叫控制         ****一般判断这个位,是否支持呼叫控制
bit1 — Command result

第3个字节
bit8 — 主动命令: REFRESH
bit7 — 主动命令:POLLING OFF
bit6 — 主动命令:POLL INTERVAL
bit5 —- 主动命令:PLAY TONE
bit4 — 主动命令:MORE TIME
bit3 — 主动命令:GET INPUT
bit2 — 主动命令:GET INKEY
bit1 — 主动命令: DISPLAY TEXT

第4个字节
bit8 — 主动命令 PROVIDE LOCAL INFORMATION (NMR/GERAN)
bit7 — 主动命令:PROVIDE LOCAL INFORMATION (MCC, MNC, LAC, Cell ID & IMEI)
bit6 — 主动命令:SET UP MENU
bit5 —- 主动命令:SET UP CALL
bit4 — 主动命令:SEND USSD
bit3 — 主动命令:SEND SS
bit2 — 主动命令:SEND SHORT MESSAGE with 3GPP-SMS-TPDU
bit1 — 主动命令: SELECT ITEM

第5个字节
bit8 — 事件:Card reader status
bit7 — 事件:Idle screen available
bit6 — 事件:User activity
bit5 —- 事件:Location status
bit4 — 事件:Call disconnected
bit3 — 事件:Call connected
bit2 — 事件:MT call
bit1 — 主动命令: SET UP EVENT LIST

第6个字节
bit8 — 事件:Network Search Mode Change
bit7 — 事件: Local Connection
bit6 — 事件: Display parameters changed
bit5 —- 事件: Access Technology Change
bit4 — 事件:Channel status
bit3 — 事件:Data available
bit2 — 事件:Browser Termination
bit1 — 事件: Language selection

第7个字节
bit8 — RFU
bit7 — RFU
bit6 — RFU
bit5 —- GET READER STATUS (Card reader identifier)
bit4 — GET READER STATUS (Card reader status)
bit3 — PERFORM CARD APDU
bit2 — POWER OFF CARD
bit1 — POWER ON CARD

第8个字节
bit8 — Call Control
bit7 — SETUP CALL
bit6 — RUN AT COMMAND
bit5 —- SET UP IDLE MODE TEXT
bit4 — GET INKEY
bit3 — 主动命令: PROVIDE LOCAL INFORMATION (date, time and time zone)
bit2 — 主动命令: TIMER MANAGEMENT (get current value)
bit1 — 主动命令: TIMER MANAGEMENT (start, stop)

第9个字节
bit8 — 主动命令: PROVIDE LOCAL INFORMATION (Access Technology)
bit7 — 主动命令:LAUNCH BROWSER (i.e. class “ab” is supported)
bit6 — 主动命令:LANGUAGE NOTIFICATION
bit5 —- 主动命令:PROVIDE LOCAL INFORMATION, Timing Advance
bit4 — 主动命令: PROVIDE LOCAL INFORMATION (language)
bit3 — 主动命令: PROVIDE LOCAL INFORMATION (NMR)
bit2 — SEND DTMF command
bit1 — DISPLAY TEXT

第10个字节(软键支持)
b8-b3 RFU
b2 —- Soft Keys support for SET UP MENU
b1 — Soft Keys support for SELECT ITEM

第11字节(保留给软键支持,软键的数目,最小为2,最大254, FF表示未用)

第12字节(Bearer Independent protocol主动命令)
….
第18字节

bit8 — 主动命令: PROVIDE LOCAL INFORMATION (Search Mode change)
bit7 — 主动命令:PROVIDE LOCAL INFORMATION (IMEISV)
bit6 — Call control on GPRS
bit5 —- 主动命令:PROVIDE LOCAL INFORMATION (ESN)
bit4 — 主动命令: GET INKEY (Variable Timeout)
bit3 — USB (Bearer Independent protocol supported bearers)
bit2 — 主动命令: GET INKEY (help is supported while waiting for immediate response or variable timeout)
bit1 — 主动命令: DISPLAY TEXT (Variable Time out)


第31字节
bit8 — 主动命令: Profile Container, Envelope Container, COMMAND CONTAINER and ENCAPSULATED SESSION CONTROL
bit7 — Support for IMS Registration event
bit6 — Support for Incoming IMS Data event
bit5 — Support of CAT over the modem interface
bit4 — Communication Control for IMS
bit3 — Confirmation parameters supported for OPEN CHANNEL in Terminal Server Mode
bit2 — Support of CSG cell discovery
bit1 — 主动命令: Contactless State Changed

第34字节
bit8 — Deprecated 始终为0
bit7 — Extended Rejection Cause Code in Event: Network Rejection for E-UTRAN
bit6 —- REFRESH with “eUICC Profile State Change” mode
bit5 — 主动命令: PROVIDE LOCAL INFORMATION (E-UTRAN Timing Advance Information)
bit4 —- Media Type “Video” supported for SET UP CALL and Call Control by USIM
bit3 — Media Type “Voice” supported for SET UP CALL and Call Control by USIM
bit2 — IMS URI supported for SET UP CALL
bit1 —URI support for SEND SHORT MESSAGE

GSM SIM卡初始化全过程

SIM上电物理激活后, ME(modem设备)选择一个目录 DF_gsm
并且 可选地尝试选择一个EF_ecc文件(如果EF_ecc可用的花),ME请求紧急呼叫代码
1. ME请求Extended Language Preference(扩展语言首选项)(File ID: 2F05)
如果:
1) EF_PL (2F05) 不可用
2) EF_PL 中的条目 不满足 ISO 639定义的语言
3) ME不支持 EF_PL 中的任何语言
三者满足其一, 那么ME就 只请求 EF_LP (6F05)
如果EF_PL和EF_LP都不存在,或者没有任何语言被ME支持, 那么ME 会选择它默认的语言。

2. 运行CHV1 验证过程;

3. 如果 CHV1 验证成功, ME开始 SIM Phase请求
4. 如果SIM要求Profile Download, 那么ME执行 Profile Download 过程(按照 3GPP TS 51.014标准)
当SIM卡启用BDN事, 那么Profile Download过程将用来 指明 ME是否支持 “SIM决定的呼叫控制”
如果支持, 那么SIM卡能够允许 对 EF_IMSI和 EF_LOCI执行 Rehabilitate 命令
5. 如果 ME检测到 SIM卡是Phase 1的,
它将忽略 FDN相关的过程,继续执行 Administrative Information请求
它也将忽略没有定义在Phase 1阶段的一些特性,比如 Higher Priority PLMN搜索周期请求。

对于Phase 2及以后的SIM卡,只有满足下面两个条件之一时才会继续GSM操作:
1) EF_IMSI和EF_LOCI没有被 invalidated, GSM操作应该立即开始
2) EF_IMSI和 EF_LOCI被invalidated, ME应该rehabiliteate这个两个EF

如果SIM卡上的FDN被启用,没有FDN能力但是有呼叫控制能力的ME, 不应该 rehabilitate 卡上的EF_IMSI和EF_LOCI文件,所以也不能访问这两个EF,
GSM操作应被禁止。

没有FDN能力,也没有呼叫控制能力的ME, 更加不能访问 EF_IMSI和EF_LOCI,GSM同样也被禁止。

SIM卡的FDN和BDN都被启用时,如果ME支持FDN但不支持呼叫控制, rehabilitate操作也不能成功,
因为REHABILITATE命令同BDN特性关联。

6. 接着运行下面的过程:
1) 管理信息(Administrative Information)请求
2) SIM 服务表 请求
3) IMSI 请求
4) 访问控制(Access Control)请求
5) 高优先级 PLMN 搜索周期 请求
6) Investigation scan 请求
7) PLMN selector请求
8) 带访问控制技术的HPLMN选择 请求
9) 用户控制的带访控制技术的PLMN选择器 请求
10) 运营商控制的带访控制技术的PLMN选择器 请求
11) 位置信息(Location Information)请求
12) GPRS位置信息请求
13) Cipher Key请求
14) GPRS Cipher Key请求
15) BCCH 信息请求
16) CPBCCH信息请求
17) 禁止的PLMN请求
18) LSA 信息请求
19) CBMID请求
20) 解个人化控制键请求
21) 告警网络提示 请求
如果在 SST服务表中表明 支持proactrive 服务,ME也支持proactive,
那么在空闲时间,每30秒,应发送一个STATUS命令
在通话过程中,也应发送STATUS命令,来检测sim卡是否存在。

rus jni

参考资料:
https://docs.rs/jni/latest/jni/
https://github.com/jni-rs/jni-rs/tree/master/example

首先,创建一个 HelloWorld.java 文件

class HelloWorld {
    private static native String hello(String input);

    static {
        System.loadLibrary("mylib");
    }

    public static void main(String[] args) {
        String output = HelloWorld.hello("josh");
        System.out.println(output);
    }
}

编译这个文件,并生成 .h 头文件

javac -h . HelloWorld.java
或者用全路径
/usr/lib/jvm/java-11-openjdk-amd64/bin/javac  HelloWorld.java  -h .

可以看到 生成了一个HelloWorld.h文件

3. 创建rust 库

cargo --lib new mylib

4. 编辑Cargo.toml

...

[dependencies]
jni = "*"

[lib]
crate_type = ["cdylib"]

5. 创建 mylib/src/lib.rs

use jni::JNIEnv;
use jni::objects::{JClass, JString};
use jni::sys::jstring;

#[no_mangle]
pub extern "system" fn Java_HelloWorld_hello(env: JNIEnv,
                                             _: JClass,
                                             input: JString)
                                             -> jstring {
    let input: String = env.get_string(input).expect("Couldn't get java string!").into();

    let output = env.new_string(format!("Hello, {}!", input))
        .expect("Couldn't create java string!");

    output.into_inner()
}

6. 编译运行

cd mylib
cargo build
cd ..
LD_LIBRARY_PATH=/path/to/mylib/target/debug java HelloWorld
或者
java -Djava.library.path=mylib/target/debug/ HelloWorld

rust自动解引用与强制解引用

Rust 有一个叫 自动引用和解引用(automatic referencing and dereferencing)的功能。方法调用是 Rust 中少数几个拥有这种行为的地方。

他是这样工作的:当使用 object.something() 调用方法时,Rust 会自动为 object 添加 &、&mut 或 * 以便使 object 与方法签名匹配。也就是说,这些代码是等价的:

p1.distance(&p2);
(&p1).distance(&p2);

第一行看起来简洁的多。这种自动引用的行为之所以有效,是因为方法有一个明确的接收者———— self 的类型。在给出接收者和方法名的前提下,Rust 可以明确地计算出方法是仅仅读取(&self),做出修改(&mut self)或者是获取所有权(self)。


println! 宏也可以自动解引用


强制解引用(Deref coercion) 是一种执行在函数和方法的参数上的便利。它只能用于那些实现了Deref trait的类型。
强制解引用,将一种类型的引用转换成另一种类型的引用。比如它可将 &String 转换成 &str
因为 String实现了 Deref trait, 返回一个 &str

当我们传递一个特定类型的的值的引用给一个函数/方法时,如果同函数/方法中定义的参数类型不匹配时,会自动进行解引用。一系列 deref 方法会被调用,用来在我们提供的类型,和参数所需要的类型之间 实施转换。

程序员在写函数/方法时, 不必要添加 许多 明示的 引用 (&)或者解引用(*)
强制解引用也让我们写的代码更好地同时工作在 引用/智能指针上。

用python给美团walleID设置id

#!/usr/bin/python3

import sys

def getvaluefrombytes(tbytes):
    va = 0
    for j in range(len(tbytes)):
        va += tbytes[j] * 256 ** j
    return va


def decodebytesfromnum(num, lens=4):
    tbytes = bytearray()
    for i in range(lens):
        tbytes.append((num & (0xff << 8 * i)) >> 8 * i)
    return tbytes


def set_cid(readbytes, channelname):
    
    # find End of central directory
    for i in range(len(readbytes) - 22):
        if (readbytes[-22 - i] == 0x50 and readbytes[-21 - i] == 0x4b and readbytes[-20 - i] == 0x05 and readbytes[
                -19 - i] == 0x06):
            break
            

    start_central_directory_value_pos = -6 - i
    start_central_directory = readbytes[start_central_directory_value_pos + 3] * 256 ** 3  \
        + readbytes[start_central_directory_value_pos + 2] * 256 ** 2                      \
        + readbytes[start_central_directory_value_pos + 1] * 256                           \
        + readbytes[start_central_directory_value_pos]

    if readbytes[start_central_directory - 16:start_central_directory] == 'APK Sig Block 42'.encode("utf-8"):
        print("check v2 true")
    else:
        print("check v2 fail")
        return


    sign_block_size = 0
    sgin_block_value_pos = start_central_directory - 16 - 8
    for i in range(8):
        sign_block_size += 256 ** i * readbytes[sgin_block_value_pos + i]

    sign_block_start_pos = start_central_directory - sign_block_size - 8

    k = 0;
    keybytes = {}
    tempbytes = []
        
    strkey = 0
    k = 0
    
    #walleid 0x71777777
    walleIDbytes = bytearray()
    walleIDbytes.append(0x77)
    walleIDbytes.append(0x77)
    walleIDbytes.append(0x77)
    walleIDbytes.append(0x71)

    pairlen = 0
    for i in range(sign_block_start_pos + 8, sgin_block_value_pos):
        tempbytes.append(readbytes[i])
        if k == 7:
            pairlen = getvaluefrombytes(tempbytes)
            tempbytes.clear()
        if k == 11:
            strkey = getvaluefrombytes(tempbytes)
            tempbytes.clear()
        if k == pairlen + 7:
            keybytes[strkey] = bytes(tempbytes)
            tempbytes.clear()
            k = -1
        k += 1


    channel = "{\"channel\":\"%s\"}" % channelname
    channelbytes = bytearray(channel.encode("utf-8"))
    if len(channelbytes) > 252:
        print(" channel str len < 252")
        return
        
    insertbytes = bytearray()
       
    channelbytes_len = len(channelbytes) + 4
    insertbytes.append(channelbytes_len)
    for i in range(7):
        insertbytes.append(0)

    for i in walleIDbytes:
        insertbytes.append(i)
    for i in channelbytes:
        insertbytes.append(i)


    start_central_directory += len(insertbytes)
    dictoffsetbytes = decodebytesfromnum(start_central_directory)
    for index in range(4):
        readbytes[start_central_directory_value_pos + index] = dictoffsetbytes[index]
    sign_block_size += len(insertbytes)
    signsizebytes = decodebytesfromnum(sign_block_size, 8)
    for index in range(8):
        readbytes[sign_block_start_pos + index] = signsizebytes[index]
        readbytes[sgin_block_value_pos + index] = signsizebytes[index]
    for b in insertbytes[::-1]:
        readbytes.insert(sgin_block_value_pos, b)

    outfilepath = "channel_%s.apk" % channelname
    with open(outfilepath, "wb") as fout:
        fout.write(readbytes)







def main():
    if len(sys.argv) != 3:
        print("i need apk_path and channel_id.")
        exit(-1)

    filepath = sys.argv[1]
    cid      = sys.argv[2]

    readbytes = bytearray()
    with open(filepath, "rb") as f:
        readbytes = bytearray(f.read())

    set_cid(readbytes, cid)


if __name__ == "__main__":
    main()