• [原]百度公交离线数据格式分析——4.小结


    还有两个问题没有解决。

    (1) prov_city_list.json 下载后,如果变为 com.baidu.bus.f.b 的对象的?

    在 3.加载城市列表 的第 14 步中,hObject 的成员 c 被赋了一个值,类型就是 com.baidu.bus.f.a,向上找这个对象是如何生成的:

    invoke-static {v0, p1}, Lcom/baidu/bus/net/a/b;->a(Ljava/lang/String;Lcom/baidu/a/a/m;)Lcom/baidu/bus/f/a;
    move-result-object v0

    看来是 com.baidu.bus.net.a.b 类的一个静态方法,传入了两个参数,第一个是解码(UTF-8)后的字符串文本,第二个是该函数(com.baidu.bus.net.a.c类的a() 方法)传进来的 com.baidu.a.a.m 的对象。在 com.baidu.bus.net.a.b 类的 a() 方法中,有这个代码:

    iget-object v1, p1, Lcom/baidu/bus/base/f;->b:Ljava/lang/String;
    invoke-static {v1}, Lcom/baidu/bus/net/a/g;->a(Ljava/lang/String;)Lcom/baidu/bus/f/a;

    调用了 com.baidu.bus.net.a.g 的 a() 方法,并传入了 com.baidu.bus.base.f 类的对象,实际就是第二个参数,com.baidu.a.a.m 是派生类。通过3.2的第(9)步,我们知道,这个实例的b成员的值是字符串“city_list”,在com.baidu.bus.net.a.g 类的 a() 方法中,有这样的代码:

    :cond_0
    const-string v1, "city_list"
    invoke-virtual {p0, v1}, Ljava/lang/String;->equals(Ljava/lang/Object;)Z
    move-result v1
    if-eqz v1, :cond_1
    new-instance v0, Lcom/baidu/bus/f/b;
    invoke-direct {v0}, Lcom/baidu/bus/f/b;-><init>()V

    在这里创建了com.baidu.bus.f.b 的对象。在 com.baidu.bus.net.a.b 类中,取得这个 com.baidu.bus.f.b对象后,调用了它的 a() 方法:

    move-result-object v1
    invoke-virtual {v1, v0}, Lcom/baidu/bus/f/a;->a(Lcom/baidu/bus/base/e;)Lcom/baidu/bus/f/a;

    通过查看 com.baidu.bus.f.b 类的 a() 方法,只不过是将JSONObject 中的 allList 和 hotCityList 进行解析,分别放到它的成员b和a(都是ArrayList)中。
    至于JSON的解析,可以看到

    new-instance v0, Lcom/baidu/bus/base/e;
    invoke-direct {v0, p0}, Lcom/baidu/bus/base/e;-><init>(Ljava/lang/String;)V

    这里利用了 com.baidu.bus.base.e 这个类,查看可知,它是从 JSONObject 派生的,实际的解析也是库函数。

    (2) 每个省份包含的城市的详细信息,是如何取得的?

    3.加载城市列表 介绍了获取 prov_city_list.json 的过程,下载的动作主要是在 com.baidu.bus.activity.ch 类中的进行的,已经知道这个类是从 AsyncTask 派生的,这个类有一个 onPostExecute() 方法,是在 doInBackground() 方法执行完成后,交给 UI 线程执行的动作。查看 ch 类重载了这个方法,除了将弹出的提示框的背景图片改为 loading_desc_checkofflinedatastatus(id 为 0x7f0200c9):

    (原图是透明背景,白色字体,在这里为了显示方便,改为黑色背景)

    更重要的,是调用了 OfflineDataManageActivity 里面的方法 j

    iget-object v0, p0, Lcom/baidu/bus/activity/ch;->a:Lcom/baidu/bus/activity/OfflineDataManageActivity;
    invoke-static {v0}, Lcom/baidu/bus/activity/OfflineDataManageActivity;->j(Lcom/baidu/bus/activity/OfflineDataManageActivity;)V

    查看 OfflineDataManageActivity 里面的j方法,有两个循环,分别是对OfflineDataManageActivity 里的 M 和 N 两个成员(都是List类型)里面的每个元素,逐一调用 b() 方法:

    check-cast v0, Lcom/baidu/bus/b/a;
    invoke-direct {p0, v0}, Lcom/baidu/bus/activity/OfflineDataManageActivity;->b(Lcom/baidu/bus/b/a;)V

    查看b() 方法,对传入的参数调用了另外一个成员 cm 的 execute() 方法,查看 cm 类,从 AsyncTask 派生,它的 doInBackground() 方法里调用它的 a() 方法,里面有如下代码:

    iget v3, v0, Lcom/baidu/bus/b/a;->a:I
    invoke-static {v3}, Ljava/lang/String;->valueOf(I)Ljava/lang/String;
    move-result-object v3
    invoke-direct {v2, v3}, Ljava/lang/StringBuilder;-><init>(Ljava/lang/String;)V
    invoke-virtual {v2}, Ljava/lang/StringBuilder;->toString()Ljava/lang/String;
    move-result-object v2
    invoke-virtual {v1, v2}, Lcom/baidu/bus/a/b;->a(Ljava/lang/String;)Lcom/baidu/bus/net/bean/update/DataUpdateInfo;
    move-result-object v1

    根据上下文得知,v0 是传入的参数,v1 是 com.baidu.bus.a.b 的实例,它的 a() 方法是根据传入的参数构造了一个URL:
    http://bs.baidu.com/offlinebusdata/{engineVersion}/{cityId}/meta.txt
    上面的 engineVersion 为3(这个值是通过com.baidu.bus.d.b.a.a().d() 取得的,真正的值是在 JNI 即 libbusoffline.so 中,分析的过程在后面),cityId 就是从 prov_city_list.json 中解析出来的每个城市的id项。以北京为例,cityId 为131,那么构造的URL为:
    http://bs.baidu.com/offlinebusdata/3/131/meta.txt
    它返回一个JSON对象:

    {"description":"",
    "downloadPath":"http://bs.baidu.com/offlinebusdata/3/131/131_14082210.dat",
    "MD5":"FAF26F270C83F1628DFAD85E16E2326E",
    "versionCode":"14082210",
    "engineVersion":3,
    "size":10560011}

    这个就一目了然了。通过分析,我们知道,OfflineDataManageActivity 类里面的成员 M 是“已下载城市”,N 是“热门城市”。

    从上面的分析可知,百度公交离线数据的下载方式是这样的:

    1. 从 http://bs.baidu.com/offlinebusdata/prov_city_list.json 获取所有城市信息;
    2. 单个城市的信息通过 http://bs.baidu.com/offlinebusdata/3/{cityId}/meta.txt 获取;
    3. 该城市的离线数据从第2步中取得的 downloadPath 项获取。


    在实际的操作中,可以不必分析这些smali文件,对于这个简单任务,使用 Wireshark 或者 tcpdump 之类的工具查看一下网络请求,就可以轻松得出结论。
    但是,这样下载后的文件是乱码一样的东西,下面逐步解密该文件的格式。

  • 相关阅读:
    Codeforces 912 D. Fishes (贪心、bfs)
    Codeforces 908 D.New Year and Arbitrary Arrangement (概率&期望DP)
    HDU
    HDU
    POJ-2299 Ultra-QuickSort (树状数组)
    deque!
    HDU
    乘法逆元
    Codeforces 911D. Inversion Counting (数学、思维)
    Codeforces 909E. Coprocessor (拓扑、模拟)
  • 原文地址:https://www.cnblogs.com/zhangbaoqiang/p/5141748.html
Copyright © 2020-2023  润新知