精华内容
下载资源
问答
  • Android 文件格式

    千次阅读 2010-06-26 18:12:00
    文件格式描述: Android 的相关文件类型: Java---应用程序源文件 Android 本身相当一部分是由 java 编写而成,而且 android 应用必须使用 java 开发 Class---java 编译后的目标文件 是由 java 虚拟机编译而成一个...

    文件格式描述:


    Android 的相关文件类型:


    Java---应用程序源文件


    Android 本身相当一部分是由 java 编写而成,而且 android 应用必须使用 java 开发

     
    Class---java 编译后的目标文件

    是由 java 虚拟机编译而成一个字节码文件,在之前我们用所学的 j2ee 以及 j2se 它是一个可
    执行文件,但是在 Android 当中它只是一个目标文件即过渡文件

    Dex---Android 平台可执行文件:


    Android 自己提供了一个虚拟机(Dalvik),这种虚拟机执行的并非 java 字节码,而是另一
    种字节码:dex 格式的字节码,在 JVM 将 java 文件编译成 Class 文件后,再次通过 Android
    平台工具将此 Class 文件转换成 dex 字节码

    Apk 文件---Android 上的安装文件

    Apk 是 Android 安装包的扩展名,一个 Android 安装包包含了与某个 Android 应用程序相
    关的所有文件,apk 文件将 androidManifest.xml 文件,应用程序代码(dex 文件)资源文
    件和其他文件打成一个压缩包,一个工程只能打进一个 apk 文件(有点类似 exe 文件)          

    展开全文
  • 文章目录@[toc]OATART 虚拟机生成 OAT 文件OAT 文件格式将 OAT 文件转换成 DEX 文件 ...对新版本的 Android 程序进行安全研究,无论是对 OAT 文件的 Hook 还是加密保护,都要了解 OAT 文件格式 A...

    OAT

    • OAT 文件是在 Android 4.4 中引入的。OAT 是优化过的、用于 ART 虚拟机执行的 DEX 文件,类似 Dalvik 的 ODEX
    • 对新版本的 Android 程序进行安全研究,无论是对 OAT 文件的 Hook 还是加密保护,都要了解 OAT 文件格式

    ART 虚拟机

    • ART 使用 AOT(Ahead-of-Time)编译技术,在 APK 第一次安装或系统升级、重启时,通过调用 dex2oat 命令将 APK 中的 DEX 文件静态编译成 OAT 并存放到 Android 设备的 /data/dalvik-cache 或 /data/app/package 目录。dex2oat 与 dexopt 不同,dex2oat 更像一个编译器,将 DEX 中的 Dalvik 字节码编译成 Native 机器码。经过这样的操作,以后启动程序时,ART 就会提高 APK 的启动速度,从而执行生成的 OAT 文件而不是 APK 中的 DEX 文件。从 Android 5.0 开始,系统默认将 ART 作为虚拟机,程序运行速度明显变快。但有个缺点,即 OAT 的静态编译操作会影响 APK 的安装效率,导致 Android 4.4 后 APK 安装速度更长。为了使运行和安装速度都更快,Android 7.0 增加了 JIT(just-in-Time)编译。新版本的 Android 使用的是基于 JIT on AOT 的编译技术

    生成 OAT 文件

    • 系统在安装 APK 时,会调用 dex2oat 自动生成 OAT 文件。也可手动执行 dex2oat 命令,为指定的 DEX 生成 OAT 文件
    • 具体操作:在执行 dex2oat 命令时使用 --dex-file 参数指定传入的 DEX 路径(若有多个 DEX,可多次指定该参数),然后为 --oat-file 参数指定 OAT 的输出路径(在指定传入的路径时,该路径要对当前的 adb shell 用户有可写权限)
    • 以 crackme0201.apk 为例,执行如下命令可生成 crackme0201.oat:
      在这里插入图片描述

    OAT 文件格式

    • 和 ODEX 一样,OAT 也有自己的格式。Android 原生程序以 ELF 格式作为程序格式基础,并在此基础上增加了属于 Android 的应用程序二进制接口(Application Binary Interface, ABI)

    • arm-linux-androideabi 中包含 ELF 文件格式在 Android 上的参数传递、浮点指针、栈展开、异常处理等规范信息。OAT 文件格式在设计之初就考虑到最终执行的程序是 ELF 格式的这一事实,为避免过多的文件格式设计带来的麻烦,最终将 OAT 文件格式完全融入 Android 所特有的 ELF 格式

    • 执行 file 命令,查看之前生成的 crackme0201.oat 文件的格式:
      在这里插入图片描述

    • file 命令根据文件头 magic 与布局格式,识别出这是一个 ARM Linux 动态链接的 ELF 文件。Android 特有的 ELF 文件格式之后会学到,这里只关注 OAT 在 ELF 上的特别部分

    • 下面是一幅 OAT 文件格式图,可看到,整个 OAT 文件都已嵌入 ELF 文件
      在这里插入图片描述

    • 试别 OAT 文件格式的一个有效方法是查看该 ELF 文件的符号表。使用 Android NDK 包中的 readelf 工具查看 crackme0201.oat 的符号表,结果如下:
      在这里插入图片描述

    • 在执行上述操作前,先要在 AS 中下载 NDK,然后将 readelf 的路径添加到环境变量
      在这里插入图片描述
      在这里插入图片描述

    • 一个 OAT 文件必须包含 oatdata、oatexec、oatlastword 三个符号

    • oatdata 符号指向的地址是 OAT 所在 ELF 的 .rodata 段,这里存放的是 OAT 文件头 OATHeader、OAT 的 DEX 文件头 OATDexFile、原始的 DEX 文件 DexFile、OAT 的 DEX 类 OatClass 等信息

    • oatexec 符号指向的地址是 OAT 所在 ELF 的 .text 段,这里存放的是编译生成的 Native 指令代码

    • oatlastword 符号指向的地址是 OAT 文件结束处在 ELF 中的文件偏移,通过它可确定 OAT 文件的内容在哪里结束

    • OATHeader 被定义成了 C++ 的类,可在 Android 源码文件 art/runtime/oat.h 中找到它的定义。将 OATHeader 转换成 C 语言的结构体后,定义:

    struct OatHeader {
    	uint8_t magic[4];
    	uint8_t version[4];
    	uint32_t adler32_checksum;
    	
    	InstructionSet instruction_set;
    	uint32_t instruction_set_features_bitmap;
    	uint32_t dex_file_count;
    	uint32_t executable_offset;
    	uint32_t interperter_to_interpreter_bridge_offset;
    	uint32_t interpreter_to_compiled_code_bridge_offset;
    	uint32_t jni_dlsym_lookup_offset;
    	uint32_t quick_generic_jni_trampoline_offset;
    	uint32_t quick_imt_conflict_trampoline_offset;
    	uint32_t quick_resolution_trampoline_offset;
    	uint32_t quick_to_interpreter_bridge_offset;
    	
    	int32_t image_patch_delta;
    	uint32_t image_file_location_oat_checksum;
    	uint32_t image_file_location_oat_data_begin;
    	
    	uint32_t key_value_store_size;
    	uint8_t key_value_store[0];
    };
    
    • 主要关注这几个字段:
    • magic:文件的标识,固定为“oat\n”,表示 OAT 的头部
    • version:OAT 的文件格式版本
    • adler32_checksum:OAT 的 adler32 校验和
    • instruction_set:OAT 文件使用的指令集。它的定义位于 art/runtime/arch/instruction_set.h 文件中,可以取如下值(与在 Android NDK 支持的 Native 指令平台上的值一致)。目前在 Android 平台上广泛使用的是 kArm,表示 ARM 指令集
    enum InstructionSet {
    	kNone,
    	kArm,
    	kArm64,
    	kThumb2,
    	kX86,
    	kX86_64,
    	kMips,
    	kMips64
    };
    
    • dex_file_count:OAT 中包含的 DEX 文件个数。对普通的 APP,该值通常是 1;对一些特殊的 OAT 文件,如系统的 boot.oat,就会包含多个 DEX 文件

    • executable_offset:oatexec 符号所在段的开始位置与 oatdata 符号所在段的开始位置的偏移量。该值通常等于 oatdata 符号所在段 .rodata 的大小

    • jni_dlsym_lookup_offset:在执行过程中,若类方法要调用的另外一个方法是 JNI 函数,则要通过 jni_dlsym_lookup_offset 字段指向的一段代码来调用

    • OatHeader 下面是 OatDexfile 结构。在 OatHeader 的 dex_file_count 字段中有多少个 DexFile,这里就会连续有多少个 OatDexFile。OatDexFile 结构的声明位于 Android 源码文件 art/runtime/oat_file.h 中,转换成 C 语言的结构体的定义:

    struct OatDexFile {
    	uint32 dex_filename_size;
    	char dex_filename_data[dex_filename_size];
    	uint32 dex_file_checksum;
    	uint8_t* dex_file_pointer;
    	uint32_t* oat_class_offsets;
    };
    
    • dex_filename_size 字段:指定 dex_filename_data 字段所占字节数,表示的是 OAT 的原 DEX 文件的完整路径

    • dex_filename_data 字段:存放 DEX 文件的完整路径

    • dex_file_checksum 字段:存放 DEX 文件的校验和

    • dex_file_pointer 字段:存放 DexFile 结构体距离当前段的文件偏移

    • oat_class_offsets 字段:指向 OatClass 的偏移列表

    • OatDexFile 数组下面是 DexFile 结构体数组,其中存放的是一个个完整的 DEX 文件。DexFile 结构体的格式在 classes.dex 一节中已学过,如下:

    struct DexFile {
    	// directly-mapped "opt" header
    	const DexOptHeader* pOptHeader;
    	
    	// pointers to directly-mapped structs
    	// and arrays in base DEX
    	const DexHeader* pHeader;
    	const DexStringId* pStringIds;
    	const DexTypeId* pTypeIds;
    	const DexFieldId* pFieldIds;
    	const DexMethodId* pMethodIds;
    	const DexProtoId* pProtoIds;
    	const DexClassDef* pClassDefs;
    	const DexLink* pLinkData;
    	
    	// These are mapped out of the "auxillary"
    	// section, and may not be included in the file.
    	const DexClassLookup* pClassLookup;
    	const void* pRegisterMapPool;		// RegisterMapClassPool
    	
    	// points to start of DEX file data
    	const u1* baseAddr;
    	
    	// track memory overhead for auxillary strcutures
    	int overhead;
    	
    	// additional app-specific data structures associated with the DEX
    	//void* auxData;
    };
    
    • 接下来是 OatClass、OatMethod 这些与 OAT 相关的类,在 oat_file.h 可找到它们的 C++ 类的定义

    将 OAT 文件转换成 DEX 文件

    • 方法:OAT 文件中包含完整的 DEX 文件,定位 OAT 中的 DexFile 结构体,将其完整数据导出即可

    • Android 系统提供了 oatdump 命令,使用该命令的 --export-dex-to 参数可将 OAT 中的所有 DEX 文件导出,放到指定目录。如,可执行如下命令,将系统框架中的 boot.oat 内的所有 DEX 文件导出,放到手机的 /data/local/tmp 目录:
      在这里插入图片描述

    • 执行上述命令的设备为有 Root 权限的 Android 7.0 AS 模拟器

    • 接下来,将在 /data/local/tmp 目录生成的 DEX 文件 pull 到本地计算机

    • 若当前环境中没合适的 Android 设备,可尝试手动操作或编写导出工具

    • 手动操作:DEX 文件有固定的文件头 magic“dex\n035”,只要在 OAT 文件中搜索它,就可快速定位 DEX 文件头(在 DEX 文件头的 0x20 字节处保存了 DEX 文件的完整大小),这样一来,DEX 的起始位置就都知道了

    • 010 Editor 脚本链接: https://pan.baidu.com/s/1IdzSM8aOTu-xdRTVxv7rxQ 提取码: snxt

    展开全文
  • 文章目录库文件jar 包aar 包手动编写一个 aar 库APKAPK 文件结构APK 文件的生成流程APK 的安装流程通过系统程序安装(开机时安装)通过 Android 市场安装通过 adb 命令安装手机自带安装(通过 SD 卡里的 APK 文件...

    库文件

    • 一系列代码功能接口与资源数据的有机集合
    • Android SDK 即是大量库文件的集合
    • 开发兼容不同版本系统的 APK 时,要引用 Android SDK 中不同版本的 android.jar 文件(开发中使用最多的库)
    • 第三方提供的地理位置 SDK、数据统计 SDK、广告 SDK 等都是库文件
    • 引用第三方库文件可能带来安全风险(获取用户数据、监控用户行为等),应对它们的“内幕”有所了解

    jar 包

    • Android Studio 问世前,Android 平台软件开发主要用 ADT 工具包完成。ADT 工具包的 IDE 是 Eclipse,库文件使用 Java 语言中标准的 jar 包。jar 包其实是一个 zip 格式的压缩包文件,存放着编译后的 Java 代码的 class 文件的集合。因此称 jar 文件为“jar 包”
    • 查看 android.jar 的格式和内容(命令行输入 bash,进入 Bash on Ubuntu on Windows 的 Shell 模式,配置方法:https://blog.csdn.net/zlmm741/article/details/104577290 ,再输入如下命令):
    $ file android.jar
    $ unzip -l android.jar | less
    
    • 输出如下(节选):
      在这里插入图片描述
    • 输入第二条命令前可能需要先安装 unzip,命令如下:
    $ sudo apt-get install unzip
    
    • 部分对安全性要求较高的 jar 包,会对包含的 class 文件进行签名,签名信息保存在 jar 包的 META-INF 目录
    • 分析 jar 包有静态分析和动态分析两种
    • 静态分析:
    • 可使用 jd-gui 这类 jar 查看工具(下载地址:https://github.com/java-decompiler/jd-gui/releases )。jd-gui 内部会调用反编译接口,将 jar 包中的 class 文件编译成 Java 文件,并将结果显示,如下图:
      在这里插入图片描述
    • 若不习惯在 jd-gui 中查看 Java 代码,可将 jar 包反编译称 Java 文件,导入 Java 编辑器中查看。选择 jd-gui 菜单项“File” -> “Save All Sources”即可保存所有反编译出的 Java 文件
    • 动态分析:
    • PC 平台可用与系统特性相关的工具 Dtrace 或 soot 对 jar 包中的文件进行运行时跟踪
    • Android 平台没有可直接使用的工具,要用迂回的办法,即先将 jar 包集成到编写的 APK 中,再对要分析的 jar 包中的类与方法进行插桩和运行时分析
    • 在 Android 平台进行动态分析时,可参考 PC 上的方案,如 AspectJ 的面向切片编程技术。AspectJ 提供了对 jar 包中方法的侵入式 Hook 技术,可通过编写 AspectJ 脚本 Hook jar 包中的方法。Android 平台有 AspectJ 的移植版本,只要编写 Hook 实例即可,详情见之后的笔记

    aar 包

    • Android Studio 问世前:jar 包中通常只包含其所使用的代码,不包含代码所使用的资源数据;如果第三方 SDK 使用了大量的图片、声音、布局等资源,除了要将 jar 包引用到工程外,还要将 SDK 中的资源手动复制到工程中
    • Android Studio 问世后:AS 将 aar 文件作为全新的库文件格式。aar 除了可包含代码,还可包含任何在开发中用到的资源数据

    手动编写一个 aar 库

    • 启动 AS,新建工程(AS 不允许直接创建 aar 文件,要通过模块的形式在已存在的 APK 工程中添加 aar 文件),命名为“MyAar”,然后选择默认选项即可,如下图:
      在这里插入图片描述
      在这里插入图片描述
    • 在 AS 主界面点击右键,如下图:
      在这里插入图片描述
    • 选择“Android Library”,输入名称“MyLib”,如下图:
      在这里插入图片描述
      在这里插入图片描述
    • 现在工程中包含 app 和 mylib 两个模块,不对其修改,直接编译 mylib 模块的 Release 版本。编译完成后会在当前工程目录的 mylib/build/outputs/aar 目录下生成 mylib-release.aar 文件
      在这里插入图片描述
    • 执行如下命令,查看文件格式:
    file mylib/build/outputs/aar/mylib-release.aar
    
    • 输出如下:
      在这里插入图片描述
    • 由上图可知 aar 文件也是 zip 包
    • 执行如下命令,查看它的内容:
    unzip -l mylib/build/outputs/aar/mylib-release.aar
    
    • 输出如下
      在这里插入图片描述
    • 它的目录结构与 APK 文件类似
    • AndroidManifest.xml:可用于定义 aar 包的名称、编译器版本等
    • classes.jar:包含 aar 库文件中所有代码生成后的 class 文件
    • res 目录:存放所有资源
    • aidl 目录(本文件不存在):存放 AIDL 接口文件
    • assets 目录(本文件不存在):存放 Asset 资源
    • jni 目录(本文件不存在):存放编译好的不同版本的 so 库
    • libs 目录:存放 aar 包引用的第三方 jar 包

    APK

    • APK(Android Package):Android 系统的软件安装包文件
    • APK 是 Android 软件的核心和 Android 软件开发的结果,要重点关注

    APK 文件结构

    • APK 文件与其他系统中的软件包一样,也有自己的格式和组织结构。自 Android 诞生起,APK 文件的格式就没发生变化,始终使用 zip 作为其格式。在目录结构上,APK 文件也没发生变化
    • 以 Crackme0201(见https://blog.csdn.net/zlmm741/article/details/104602172 )为例,解包查看其目录结构:
    • 查看文件格式:
    file APK文件全路径
    

    在这里插入图片描述

    • 解包:
    unzip APK文件全路径
    

    在这里插入图片描述

    • 使用 tree 命令查看目录结构(先安装:sudo apt-get install tree):
      在这里插入图片描述
    • 一个完整的 APK 文件包含如下内容:
    • AndroidManifest.xml:编译好的 AXML 二进制格式的文件
    • META-INF 目录:保存 APK 的签名信息
    • classes.dex:程序的可执行代码。如果开启了 MultiDex,则会有多个 DEX 文件
    • res 目录:程序中使用的资源信息。针对不同分辨率的设备,可使用不同的资源文件
    • resources.arsc:编译好的二进制格式的资源信息
    • assets 目录:若程序使用 Asset 系统来存放 Raw 资源,所有的资源都将存放在这个目录下

    APK 文件的生成流程

    • 使用 AS 开发 Android 程序时,AS 会在系统后台调用编译器,自动生成 APK 文件
    • ADT(Android Development Tools)时代 Android 官方发布的完整 APK 编译流程图:
      在这里插入图片描述
    • 使用 aapt 打包程序资源,处理项目中的 AndroidManifest.xml 文件和 XML 布局文件,并生成 R.java 文件
    • 使用 aidl 解析 AIDL 接口,定义并生成相应的 Java 文件
    • 调用 Java 编译器生成 class 文件,使用 dx 将所有的 class 文件与 jar 包打包生成 DEX 文件,调用 apkbuilder 将上述资源与 class 文件合并成 APK 文件
    • 对 APK 进行对齐处理和签名
    • 打包生成 APK 的整个过程都基于 ADT 时代的编译工具集实现
    • 到了 Android Studio 时代,编译流程的细节发生一些变化,Android 官方使用 gradle 作为 APK 的构建工具,但没给出详细的“新版” APK 打包流程,只放出一幅新的打包流程图:
      在这里插入图片描述
    • 整个打包过程被抽象成了将编译模块和依赖项打包成 DEX 文件、将 APK Packager 打包成 APK 和签名两个步骤,底层的操作细节被掩盖

    APK 的安装流程

    • 介绍 Android 程序的四种安装方式

    通过系统程序安装(开机时安装)

    • 由开机时启动的 PackageManagerService 服务完成。这个服务在启动时会扫描系统程序目录 /system/app 并重新安装所有程序

    通过 Android 市场安装

    • 手机内置的应用商店如果放置在 /system/app 目录下,APK 的安装过程就可自动完成,通常不需要用户干预;否则会弹出软件安全界面,引导用户完成安装
    • 从 Android 6.0 开始,软件安装完成后会弹出权限控制界面,允许用户对软件所使用的权限进行细粒度的管理

    通过 adb 命令安装

    • 使用 Android SDK 提供的调试桥命令 adb 来安装 APK
    • 在命令行输入如下命令,即可完成安装:
    adb install APK全路径
    

    手机自带安装(通过 SD 卡里的 APK 文件安装)

    • 点击手机文件浏览器里的 APK 文件,直接调用 Android 系统的软件包 packageinstaller.apk,即可安装 APK

    通过分析 packageinstaller.apk 的实现步骤了解 APK 的安装过程

    • 用户通过 Android 手机的文件管理程序定位到要安装的 APK 时,只要点击 APK,就会弹出软件安装界面(点击“安装”即可开始安装,点击“取消”则返回)。这个安装界面其实是 Android 系统程序 PackageInstaller 的 PackageInstallerActivity,当 Android 系统请求安装 APK 时,就会启动这个 Activity,并接收通过 Intent 传递来的 APK 文件信息
    • PackageInstaller 的源码位于 Android 系统源码的 packages/apps/PackageInstaller 目录下。当 PackageInstallerActivity 启动时,首先初始化一个 PackageManager 对象与一个 PackageParser.Package 对象,接着调用 PackageUtil 类的静态方法 getPackageInfo() 来解析程序包信息。如果解析出错,程序执行失败并返回;如果成功,程序就调用 setContentView() 方法设置 PackageInstallerActivity 的显示视图,然后调用 PackageUtil 类的静态方法 getAppSnippet() 与 initSnippetForNewApp() 来设置 PackageInstallerActivity 的控件,以显示程序的名称和图标,最后调用 initiateInstall() 方法进行其他初始化工作
    • PackageInstallerActivity 的 onCreate() 方法代码如下:
    Protected void onCreate(Bundle icicle) {
        super.onCreate(icicle);
        // Get intent information
        final Intent intent = getIntent();
        // 获取传递来的 APK 文件信息
        mPackageURI = intent.getData();
        // 获取包管理器
        mPm = getPackageManager();
        // 解析 APK 文件
        mPkgInfo = PackageUtil.getPackageInfo(mPackageURI);
        
        // Check for parser errors
        if (mPkgInfo == null) {
        Log.w(TAG, "Parser error when parsing manifest. Discontinuing installation");
        // 解析出错,弹出出错对话框
        showDialogInner(DLG_PACKAGE_ERROR);
        setPmResult(PackageManager.INSTALL_FAILD_INVALID_APK);
        return;
        }
        
        // Set view
        // 设置试图
        setContentView(R.layout.install_start);
        mInstallConfirm = findViewById(R.id.install_confirm_panel);
        mInstallConfirm.setVisibility(View.INVISIBLE);
        // 获取 APK 的程序名和图标
        PackageUtil.AppSnippet as = PackageUtil.getAppSnippet(
            this, mPkgInfo.applicationInfo, mPackageURI);
        // 设置 APK 的程序名和图标
        PackageUtil.initSnippetForNewApp(this, as, R.id.app_snippet);
        
        // Deal with install source.
        String callerPackage = getCallingPackage();
        if (callerPackage != null && intent.getBooleanExtra(
            Intent.EXTRA_NOT_UNKNOWN_SOURCE, false)) {
            try {
                // 获取程序信息
                mSourceInfo = mPm.getApplicationInfo(callerPackage, 0);
                if (mSourceInfo != null) {
                    // 系统程序
                    if ((mSourceInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0) {
                        // System apps don't need to be approved.
                        // 其他初始化工作
                        initiateInstall();
                        return;
                    }
                    SharedPreFerences prefs = getSharedPreferences(
                        PREFS_ALLOWED_SOURCE, Context.MODE_PRIVATE);
                    if (prefs.getBoolean(mSourceInfo.packageName, false)) {
                        // User has already allowed this one.
                        // 其他初始化工作
                        initiateInstall();
                        return;
                    }
                    // Ask user to enable setting first
                    // 弹出“新的应用来源”对话框
                    showDialogInner(DLG_ALLOW_SOURCE);
                    return;
                }
            }
            catch (NameNotFoundException e) {
                
            }
        }
        // Check unknown sources.
        if (!isInstallingUnknownAppsAllowed()) {
            // Ask user to enable setting first
            // 弹出“启用未知来源”对话框
            showDialogInner(GLG_UNKNOWN_APPS);
            return;
        }
        // 其他初始化工作
        initiateInstall();
    }
    
    • 在整个 onCreate() 方法中有两个重点函数:PackageUtil 类的 getPackageInfo();initiateInstall()。getPackageInfo() 首先通过 packageURI 获取 APK 的路径,然后构造一个 PackageParser 对象,最后调用 PackageParser 对象的 parsePackage() 解析 APK 程序包。parsePackage() 代码较长,大致如下:
    public Package parsePackage(File sourceFile, String destCodePath,
        DisplayMetrics metrics, int flags) {
        ...
        try {
            assmgr = new AssetManager();
            int cookie = assmgr.addAssetPath(mArchiveSourcePath);
            ...
        }
        catch (Exception e) {
            Slog.w(TAG, "Unable to read AndroidManifest.xml of" +
                mArchiveSourcePath, e);
        }
        ...
        try {
            // XXXX todo: need to figure out correct configuration.
            pkg = parsePackage(res, parser, flags, errorText);
        }
        catch (Exception e) {
            ...
        }
        ...
        return pkg;
    }
    
    • parsePackage() 调用了另一个版本的 parsePackage(),代码如下:
    private Package parsePackage(Resources res, XmlResourceParser parser,
        int flags, String[] outError) throws XmlPullParserException, IOException {
        ...
        String pkgName = parsePackageName(parser, attrs, flags, outError);
        ...
        final Package pkg = new Package(pkgName);
        ...
        while ((type = parser.next()) != XmlPullParser.END_DOCUMENT &&
            (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
            if (type == XmlPullParser.END_TAG ||
                type == XmlPullParser.TEXT) {
                continue;
            }
            String tagName = parser.getName();
            if (tagName.equals("application)) {
                ...
                foundApp = true;
                if (!parseApplication(pkg, res, parser, attrs, flags, outError)) {
                    return null;
                }
            }
            else if (tagName.equals("permission-group")) {
                ...
            }
            ...
            else if (tagName.equals("eat-comment")) {
                ...
            }
            else if (RIGID_PARSER) {
                ...
            }
            else {
                Slog.w(TAG, "Unknown element under <manifest>: " +
                    parser.getName() + " at " + mArchiveSourcePath +
                    " " + parser.getPositionDescription());
                XmlUtils.skipCurrentTag(parser);
                continue;
            }
        }
        ...
        return pkg;
    }
    
    • 首先调用 parsePackageName() 从 AndroidManifest.xml 中获取程序包名,接着构建了一个 Package 对象,然后逐一处理 AndroidManifest.xml 中的标签。在处理 application 标签时使用了 parseApplication(),该方法负责解析 activity、receiver、service、provider,并将它们添加到传递进来的 Package 对象的 ArrayList 中
    • 在 onCreate() 中,getPackageInfo() 返回后调用了 initiateInstall()、initiateInstall() 负责检测该程序是否已安装。若已安装,就调用 startInstallConfirm() 显示安装界面;若没安装,则调用 showDialogInner(DLG_REPLACE_APP) 弹出替换程序对话框
    • startInstallConfirm() 设置了安装与取消按钮的监视器。最后是 onClick() 的按钮点击响应,安装按钮使用 startActivity() 启动一个 Activity 类 InstallAppProgress,该类在初始化 onCreate() 时调用 initView(),后者最终调用 PackageManager 类的installPackage() 来安装 APK
    • installPackage() 是 PackageManager 类的一个虚函数,PackageManagerService.java 实现了它。installPackage() 调用了 installPackageWithVerification(),该方法先验证调用者是否具有安装程序的权限,然后通过消息处理的方式调用 processPendingInstall() 进行安装。processPendingInstall() 调用了 installPackageLI()。installPackageLI() 经过一系列验证,最终调用 replacePackageLI() 或 installNewPackageLI() 来替换或安装程序。上述过程的代码如下:
    private void installPackageLi(InstallArgs args,
        boolean newInstall, PackageInstalledInfo res) {
        int pFlags = args.flags;
        String installerPackageName = args.installerPackageName;
        File tmpPackageFile = new File(args.getCodePath());
        ...
        // Set application objects path explicitly after the rename
        setApplicationInfoPaths(pkg, args.getCodePath(),
            args.getResourcePath());
        pkg.applicationInfo.nativeLibraryDir =
            args.getNativeLibraryPath();
        if (replace) {
            // 替换已安装的程序
            replacePackageLI(pkg, parseFlags, scanMode,
                installerPackageName, res);
        }
        else {
            // 安装新程序
            installNewPackageLI(pkg, parseFlags, scanMode,
                installerPackageName, res);
        }
    }
    
    • 尽管安装和替换操作的代码都较长,但它们最终都会调用 scanPackageLI()
    • scanPackageLI() 会实例化一个 PackageParser 对象,然后调用其 parsePackage() 来解析 APK 程序包。在代码的最后调用了 scanPackageLI() 的另一版本,此版本的 scanPackageLI() 将完成 APK 的依赖库检测、签名验证、sharedUser 的签名检查、Native 库目录文件的更新、组件名称的检查等工作,并调用 mInstaller 的 install() 来安装程序。mInstaller 为 Installer 类的一个实例,Installer 类的源码位于 Android 源码文件 frameworks/base/services/java/com/android/server/pm/Installer.java 中。install() 在构造字符串“install name uid gid”后,调用 transaction(),通过 socket 向 /system/bin/installd 程序发送 install 指令。installd 的源码位于 frameworks/base/cmds/installd 目录下,这个程序在开机后常驻内存,可通过在 adb 的 Shell 环境下运行 ps | grep /system/bin/installd 命令查看进程信息。installd 处理 install 指令的函数为 installd.c 文件中的 do_install(),do_install() 调用了 install(),后者在 commands.c 文件中有实现代码,大致如下:
    int install(const char* pkgname, uid_t uid, gid_t gid) {
        ...
        // 创建包路径
        if (create_pkg_path(pkgdir, pkgname, PKG_DIR_POSIFIX, 0)) {
            ALOGE("cannot create package path\n");
            return -1;
        }
        // 创建库路径
        if (create_pkg_path(libdir, pkgname, PKG_LIB_POSIFIX, 0)) {
            ALOGE("cannot create package lib path\n");
            return -1;
        }
        // 创建包目录
        if (mkdir(pkgdir, 0751) < 0) {
            ALOGE("cannot create dir '%s': %s\n",
                pkgdir, strerror(errno));
            return -errno;
        }
        // 设置包目录权限
        if (chmod(pkgdir, 0751) < 0) {
            ALOGE("cannot chmod dir '%s': %s\n",
                pkgdir, strerror(errno));
            unlink(pkgdir);
            return -errno;
        }
        // 创建库目录
        if (mkdir(libdir, 0755) < 0) {
            ALOGE("cannot create dir '%s': %s\n",
                libdir, strerror(errno));
            unlink(pkgdir);
            return -errno;
        }
        // 设置库目录权限
        if (chmod(libdir, 0755) < 0) {
            ALOGE("cannot chmod dir '%s': %s\n",
                libdir, strerror(errno));
            unlink(libdir);
            unlink(pkgdir);
            return -errno;
        }
        // 设置库目录的所有者
        if (chown(libdir, AID_SYSTEM, AID_SYSTEM) < 0) {
            ALOGE("cannot chown dir '%s': %s\n",
                libdir, strerror(errno));
            unlink(libdir);
            unlink(pkgdir);
            return -errno;
        }
        // 设置包目录的所有者
        if (chown(pkgdir, uid, gid) < 0) {
            ALOGE("cannot chown dir '%s': %s\n",
                pkgdir, strerror(errno));
            unlink(libdir);
            unlink(pkgdir);
            return -errno;
        }
        ...
        return 0;
    }
    
    • install() 执行完毕,会通过 socket 回传结果,最终由 PackageInstaller 根据返回结果进行相应的处理
    • 到此一个 APK 就安装完成
    展开全文
  • Android ELF文件格式

    千次阅读 2014-09-18 10:35:33
    Android ELF文件格式简介.

    最近一直在学习elf相关资料,有一点总结,这里记录下来,也方便以后查阅。

    ELF是类Unix类系统,当然也包括Android系统上的可执行文件格式(也包括.so和.o类文件)。可以理解为Android系统上的exe或者dll文件格式。理解ELF文件规范,是理解Android系统上进程加载、执行的前提。


    网上关于ELF的介绍已经非常多,最好的手册还是直接看ELF官方的手册。


    下面以一张非虫先生总结好的图片讲解,更加清晰:


    展开全文
  • Android5.0 文件格式改动了哪些??????????????
  • @[TOC] Android手机录音机格式记录 Android手机录音机格式记录 机型 文件格式 华为M6平板 amr 小米9 aac vivo iqoo neo3 m4a 荣耀 V20 m4a 小米 10 aac 华为 P30 m4a
  • 文件换行格式 Settings -> Editor -> Code Style -> Line separator (for new files) 选择Unix and OS X (\n) 文件编码格式 Settings -> Editor -> File Endcodings 改成UTF-8
  • android安卓java文件转kotlin格式

    千次阅读 2017-06-22 23:10:20
    下面我们要分四步完成Kotlin的配置。 新建一个Android项目。...修改Gradle代码来添加Kotlin...将Java类文件转换成Kotlin。 首先,直接以默认方式新建一个Android项目,此时应该自带一个Activity。之后,要在两
  • Android Dex文件格式(一)

    万次阅读 2018-05-29 20:32:13
    dex是Android平台上(Dalvik虚拟机)的可执行文件, 相当于... 为什么需要学习dex文件格式? 最主要的一个原因: 由于通过反编译dex文件可以直接看到java源码, 越来越多的app(包括恶意病毒app)都使用了加固技术以防止a...
  • Android 读取csv格式数据文件

    千次阅读 2020-07-20 10:35:08
    百度百科上说 CSV是逗号分隔值文件格式,也有说是电子表格的,既然是电子表格,那么就可以用Excel打开,那为什么要在Android中来读取这个.csv格式的文件呢?因为现在主流数据格式是采用的JSON,但是另一种就是.csv...
  • Android Studio 布局文件格式化代码

    千次阅读 2017-01-06 09:23:23
    Android Studio 布局文件结束标签换行插入
  • android录音MP3格式文件

    千次阅读 2017-05-18 08:57:22
    项目有录音功能,本来是录制的arm格式文件,需求让改成MP3格式,折腾半天发现android本身做不到这一点,只能借助ndk来完成,下面是ndk的配置级MP3格式文件的录制 一、ndk介绍及下载:...
  • Android本身便是基于Java开发的, 所以Java文件相当于Android的编程文件.   二.Class文件___Java文件编译后的目标文件   该文件是有Java文件经过JVM(Java 虚拟机)编译后的字节码文件, 在J2SE和J2EE中, 它是一...
  • android V2签名文件格式

    2018-11-21 14:00:51
  • Android studio上音频文件格式问题

    千次阅读 2018-11-19 20:16:37
    今天写Android音频文件的时候格式出了问题,刚刚把音频文件拖进去的时候格式是text,最后怎么改,删了重来都不行,去网上找了一个博主的解答,讲的也不是太清楚,我弄了半天,试了几种方法, 一先按照这个博主的改...
  • Android Studio 类文件乱码变成 xml 格式文件 事情发生的很莫名其妙,Android Studio 好好的,突然一些 java 类文件变成了 xml 格式的乱码,然而用 notepad++ 打开错误的 java 类文件发现是没有问题的,说明是 ...
  • 主要为大家详细介绍了Android实现文件或文件夹压缩成.zip格式压缩包,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
  • 今天在使用Android Studio时出现了布局文件格式化时代码位置出现错乱,以下为解决方式:
  • Android加载pdf格式文件

    千次阅读 热门讨论 2016-09-28 14:16:06
    pdf格式安卓界面是上无法直接展示的,但是遇到了要加载pdf格式的操作并且在界面展示出来,所以必须要想解决的方法 查找资源的过程中找到了AndroidPDFview的第三方控件,使用方法: 1、首先要在moudle的build....
  • android文件分享

    2019-05-05 15:04:40
    基于Java源码的Android上传文件小模块,运行于Android客户端,用户通过嵌入程序内的上传程序,实现文件上传,学会了本代码,不但可上传限制格式文件,还可上传指定格式的图片、文件等,android upload程序源代码,...
  • 转载声明:本文转自... 出于安全考虑,Android蓝牙在传输文件时对文件格式有限制,默认情况下,并不是所有文件都能够传输和共享。 在packages/apps/Bluetooth下面的AndroidManifest.xml中    android
  • 我们也清楚,适合于android平台使用的或许是.db格式的数据库文件了。下面说下如何将.sql格式的数据库文件利用Navicat Lite得到.db格式文件。步骤如下: 下载安装Navicat Lite 打开Navicat Lite, 连接到本地MySQL...
  • android8.0的vdex文件格式分析

    万次阅读 2017-07-18 18:18:56
    google在android8.0新增加了vdex文件,定义如下 art\runtime\ vdex_file.h // VDEX files contain extracted DEXfiles. The VdexFile class maps the file to // memory and provides tools foraccessing its ...
  • 上一篇说了float类型的保存:java float数组与文件之间的转换 大端转小端 里面说到了大端小端的问题,如果用byte格式保存就可以完美避免这个问题。 public static void saveByte(byte[] bytes, String str) { ...
  • android音频文件转换格式

    千次阅读 2019-09-19 11:13:27
    * 转换格式 */ setAndroidAudioConverterUtils(this,file,this); } public void setAndroidAudioConverterUtils(AndroidAudioConverterUtils.AndroidAudioConverterUrl androidAudioConverterUtils, ...
  • 只能简单地实现先把h264格式的视频流保存到SD卡,再把对应地h264文件转码成MP4格式文件,然后删除原H264格式文件。 实时播放实时转码成MP4还处理摸索阶段,因为我还不会用ffmpeg框架。 在网上找了很久,找到了常用的...
  • Android下面office文件格式转换

    千次阅读 2013-11-15 16:01:24
    实现原理:  依赖openoffice服务器处理。 步骤  1、首先搭建openoffice服务器器,可参考  http://blog.csdn.net/woaixinxin123/article/details/12117877  2、编写openoffice web接口    3、android利用web接
  • AndroidStudio设置预览markdown格式文件

    千次阅读 2019-06-13 17:51:53
    正常来说markdown格式文件应该是这样: 但是有的时候文件会显示成这样: 这种情况下会影响预览效果,没有特定的高亮显示: MAC版设置MD格式预览步骤: AndroidStudio -> Preferences -> Editor -> ...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 245,732
精华内容 98,292
关键字:

安卓文件格式