高中生

- 金币
- 404
- 好评
- 1
- 信誉
- 100
|
flutter某岛后,解除vip,登录,卡在了下载上。研究下来,不知道是临门一脚,还是game over了。
发上分析。
逐行代码分析
1. 函数入口与栈帧设置 (Prologue)
_ clickDownload(/* No info */) async {
// addr: 0xf5bd78, size: 0x5f4
// 注释:函数起始地址0xf5bd78,总大小0x5f4字节
// 0xf5bd78: EnterFrame
// 0xf5bd78: stp fp, lr, [SP, #-0x10]!
// 0xf5bd7c: mov fp, SP
// 分析:标准的函数入口。保存帧指针(FP)和链接寄存器(LR)到栈上,并建立新的栈帧。
// 0xf5bd80: AllocStack(0x80)
// 0xf5bd80: sub SP, SP, #0x80
// 分析:分配0x80(128)字节的栈空间用于局部变量存储。
// 0xf5bd84: SetupParameters(...)
// 0xf5bd84: stur NULL, [fp, #-8]
// 0xf5bd88: mov x0, x3
// 0xf5bd8c: stur x1, [fp, #-0x10]
// 0xf5bd90: stur x2, [fp, #-0x18]
// 0xf5bd94: stur x3, [fp, #-0x20]
// 0xf5bd98: stur x5, [fp, #-0x28]
// 分析:保存传入的参数(this指针、以及可能的Event参数)到栈帧中(fp-0x10到fp-0x28)。
// 0xf5bd9c: CheckStackOverflow
// 0xf5bd9c: ldr x16, [THR, #0x48] ; THR::stack_limit
// 0xf5bda0: cmp SP, x16
// 0xf5bda4: b.ls #0xf5c364
// 分析:检查栈溢出。加载线程(THR)中的栈限制,如果SP小于限制,则跳转到溢出处理stub。
2. 上下文初始化与异步设置
// 0xf5bda8: r1 = 2
// 0xf5bda8: mov x1, #2
// 分析:准备参数,可能用于AllocateContext。
// 0xf5bdac: r0 = AllocateContext()
// 0xf5bdac: bl #0x118589c ; AllocateContextStub
// 0xf5bdb0: mov x2, x0
// 分析:调用运行时Stub分配一个新的ExecutionContext(用于异步操作捕获变量)。
// 0xf5bdb4: ldur x1, [fp, #-0x10]
// 0xf5bdb8: stur x2, [fp, #-0x30]
// 分析:将分配的Context对象保存到栈变量(fp-0x30)中。
// ... (中间省略部分字段存储操作) ...
// 0xf5bdc8: InitAsync() -Future
// 0xf5bdc8: mov x0, NULL
// 0xf5bdcc: bl #0x943f24 ; InitAsyncStub
// 分析:初始化异步函数,创建并返回一个Future对象。
3. 核心逻辑分支:检查下载状态 (getIsDownloaded)
// 0xf5bdd0: ldur x0, [fp, #-0x10] ; 加载this
// 0xf5bdd4: LoadField: r1 = r0-field_d7 ; 加载字段
// 0xf5bdd4: ldur w1, [x0, #0xd7]
// 0xf5bdd8: DecompressPointer r1 ; 解压缩指针(Dart 2.8+压缩指针特性)
// 0xf5bdd8: add x1, x1, HEAP, lsl #32
// 0xf5bddc: tbnz w1, #4, #0xf5bde8
// 分析:加载this.field_d7(可能是_asyncCompleter或状态标记)。
// tbnz:测试第4位是否为1。如果为1(非空/已完成),跳转到0xf5bde8;
// 否则(为0),执行下面的错误处理。
// --- 分支A:条件不满足(执行ReturnAsyncNotFuture) ---
// 0xf5bde0: r0 = Null
// 0xf5bde0: mov x0, NULL
// 0xf5bde4: r0 = ReturnAsyncNotFuture()
// 0xf5bde4: b #0x943a1c ; 跳转到错误处理Stub
// 分析:如果上述条件不满足,直接跳转到异步错误返回。
// --- 分支B:条件满足(继续执行) ---
// 0xf5bde8: ... (跳过错误分支) ...
// 0xf5be00: r0 = getIsDownloaded()
// 0xf5be00: bl #0xf5c36c ; 调用getter方法
// 0xf5be04: tbz w0, #4, #0xf5bf08
// 分析:调用getIsDownloaded()方法。
// tbz:测试返回值的第4位。在Dart汇编中,布尔值和对象指针通常通过tag bit(如bit 0或bit 1)区分。
// 如果结果为false(或null),跳转到0xf5bf08(可能是显示BottomSheet的逻辑)。
4. 分支逻辑:显示模态底部弹窗 (showModalBottomSheet)
// --- 逻辑块:显示BottomSheet(当!isDownloaded) ---
// 0xf5be08: r0 = InitLateStaticField(0xde0) // User::instance
// 0xf5be08: ... (初始化静态单例User.instance) ...
// 分析:确保User单例已初始化。
// 0xf5be24: ... (获取User.instance的某个字段) ...
// 0xf5be34: r1 = LoadInt32Instr(r0)
// 0xf5be34: sbfx x1, x0, #1, #0x1f
// 分析:从对象中提取整数值(可能是用户ID或状态码)。
// 0xf5be40: cmp x1, #0
// 0xf5be44: b.gt #0xf5bee8
// 分析:比较提取的值是否0。如果大于0,跳转到0xf5bee8(跳过弹窗逻辑?或者执行不同分支)。
// --- 显示BottomSheet的代码(0xf5be48 - 0xf5bed0) ---
// 0xf5be48: ... (准备参数) ...
// 0xf5be4c: d1 = 0.650000 ; 加载浮点常量
// 0xf5be54: d0 = 0.700000 ; 加载浮点常量
// 分析:加载用于UI布局的百分比数值(例如65%, 70%屏幕高度)。
// 0xf5be5c: r0 = LoadStaticField(0xdac) ; 可能是Theme或配置
// 0xf5be64: LoadField: d2 = r0-field_7 ; 加载double值
// 0xf5be68: fmul d3, d2, d1 ; d3 = d2 * 0.65
// 0xf5be70: fmul d1, d2, d0 ; d1 = d2 * 0.70
// 分析:计算具体的像素尺寸(基于屏幕宽度或高度*百分比)。
// 0xf5be78: r0 = BoxConstraints()
// 0xf5be78: bl #0x9e647c
// 分析:创建BoxConstraints对象,用于限制弹窗大小。
// 0xf5bea0: r1 = Function '<anonymous closure':.
// 0xf5bea0: add x1, PP, #0x2c...
// 分析:加载匿名闭包函数(即BottomSheet内部的builder函数)。
// 0xf5bea8: r0 = AllocateClosure()
// 0xf5bea8: bl #0x1185c60
// 分析:分配闭包对象(Closure),捕获上下文。
// 0xf5bec8: r4 = const [0x1, 0x5, ... "backgroundColor", ...]
// 分析:加载一个常量List,这通常是Named Arguments的键值对数组,
// 用于传递给showModalBottomSheet的参数名(如backgroundColor, constraints)。
// 0xf5bed0: r0 = showModalBottomSheet()
// 0xf5bed0: bl #0xb82544
// 分析:调用showModalBottomSheet显示底部弹窗。
// (注:这段代码之后又将field_d7设为false并返回,说明这个弹窗可能是一个"确认下载"框)。
5. 主逻辑:执行下载与网络请求 (Post Request)
// --- 逻辑块:执行下载(当isDownloaded或其他条件) ---
// 0xf5bf34: r0 = getIsDownloaded() ; 再次调用getter
// 0xf5bf38: tbz w0, #4, #0xf5c338
// 分析:再次检查状态。如果为false,跳转到0xf5c338(可能是直接返回或调用回调)。
// --- 构建请求参数Map ---
// 0xf5bf50: r0 = Map._fromLiteral()
// 分析:创建一个新的Map对象用于存放请求参数。
// 0xf5bf58: r0 = InitLateStaticField(0xde0) // User::instance
// 0xf5bf74: LoadField: r2 = r0-field_7 ; 获取userId
// 0xf5bf94: r2 = "userId"
// 0xf5bf98: r0 = []=() ; map['userId'] = value
// 分析:向Map中添加"userId"键值对。
// 0xf5bfb0: r2 = "pwd" ; 添加"pwd"字段
// 0xf5bfdc: r2 = "sourceId" ; 添加"sourceId"字段
// 0xf5c000: r2 = "so |
|