apk从打包到安装到启动

apk从打包安装启动

参考学习:

打包:

http://blog.youkuaiyun.com/jason0539/article/details/44917745

安装:

http://blog.youkuaiyun.com/luoshengyang/article/details/6766010

应用启动:

http://blog.jobbole.com/67931/

http://blog.sina.com.cn/s/blog_623868100101lp2s.html

http://androidzhibinw.github.io/android/app/startup/activity/%E5%BA%94%E7%94%A8%E7%A8%8B%E5%BA%8F/%E5%90%AF%E5%8A%A8/%E5%88%86%E6%9E%90/2015/09/21/android-app-startup-process/

 

apk打包

流程概述:

1、打包资源文件,生成R.java文件

2、处理aidl文件,生成相应java 文件

3、编译工程源代码,生成相应class文件

4、转换所有class文件,生成classes.dex文件

5、打包生成apk

6、对apk文件进行签名

7、对签名后的apk文件进行对其处理

 


 

具体流程



 

 

第一步:打包资源文件,生成R.java文件。

【输入】Resource文件(就是工程中res中的文件)、Assets文件(相当于另外一种资源,这种资源Android系统并不像对res中的文件那样优化它)、AndroidManifest.xml文件(包名就是从这里读取的,因为生成R.java文件需要包名)、Android基础类库(Android.jar文件)

【工具】aapt工具(Android Asset Packaging Tool

【输出】打包好的资源(bin目录中的resources.ap_文件)、R.java文件(gen目录中)

打包资源的工具aapt大部分文本格式的XML资源文件会被编译成二进制格式的XML资源文件,除了assetsres/raw资源被原装不动地打包进APK之外,其它的资源都会被编译或者处理。 

生成过程主要是1调用了aapt源码目录下的Resource.cpp文件中的buildResource()函数,该函数首先1.1检查AndroidManifest.xml的合法性,然后1.2res目录下的资源子目录进行处理,处理的函数为makeFileResource(),处理的内容包括1.2.1资源文件名的合法性检查,1.2.2向资源表table添加条目等,处理完后调用compileResourceFile()函数1.3编译resasserts目录下的资源并生成resources.arsc文件,compileResourceFile()函数位于aapt源码目录的ResourceTable.cpp文件中,该函数最后会调用parseAndAddEntry()函数1.4生成R.java文件,完成资源编译后,接下来调用compileXmlfile()函数2res目录的子目录下的xml文件分别进行编译,这样处理过的2.1xml文件就简单的被加密了,最后将所有的资源与编译生成的resorces.arsc文件以及加密过的AndroidManifest.xml文件2.2打包压缩成resources.ap_文件(使用Ant工具命令行编译则会生成与build.xml“project name”指定的属性同名的ap_文件)。

关于这一步更详细的流程可阅读http://blog.youkuaiyun.com/luoshengyang/article/details/8744683

第二步:处理aidl文件,生成相应的java文件。

【输入】源码文件、aidl文件、framework.aidl文件

【工具】aidl工具

【输出】对应的.java文件

对于没有使用到aidlandroid工程,这一步可以跳过。aidl工具解析接口定义文件并生成相应的java代码供程序调用。

 

第三步:编译工程源代码,生成下相应的class文件。

【输入】源码文件(包括R.javaAIDL生成的.java文件)、库文件(.jar文件)

【工具】javac工具

【输出】.class文件

这一步调用了javac编译工程src目录下所有的java源文件,生成的class文件位于工程的bin\classes目录下,上图假定编译工程源代码时程序是基于android SDK开发的,实际开发过程中,也有可能会使用android NDK来编译native代码,因此,如果可能的话,这一步还需要使用android NDK编译C/C++代码,当然,编译C/C++代码的步骤也可以提前到第一步或第二步。

 

第四步:转换所有的class文件,生成classes.dex文件。

【输入】 .class文件(包括Aidl生成.class文件,R生成的.class文件,源文件生成的.class文件),库文件(.jar文件)

【工具】javac工具

【输出】.dex文件

前面多次提到,android系统dalvik虚拟机的可执行文件为dex格式,程序运行所需的classes.dex文件就是在这一步生成的,使用的工具为dxdx工具主要的工作是将java字节码转换为dalvik字节码、压缩常量池、消除冗余信息等。

 

第五步:打包生成apk。

【输入】打包后的资源文件、打包后类文件(.dex文件)、libs文件(包括.so文件,当然很多工程都没有这样的文件,如果你不使用C/C++开发的话)

【工具】apkbuilder工具

【输出】未签名的.apk文件

打包工具为apkbuilderapkbuilder为一个脚本文件,实际调用的是android-sdk\tools\lib\sdklib.jar文件中的com.android.sdklib.build.ApkBuilderMain类。它的代码实现位于android系统源码的sdk\sdkmanager\libs\sdklib\src\com\android\sdklib\build\ApkBuilderMain.java文件,代码1构建了一个ApkBuilder类,然后2以包含resources.arsc的文件为基础生成apk文件,这个文件一般为ap_结尾,接着调用addSourceFolder()函数3添加工程资源,addSourceFolder()会调用processFileForResource()函数往apk文件中添加资源,处理的内容包括res目录与asserts目录中的文件,添加完资源后调用addResourceFromJar()4函数往apk文件中写入依赖库,接着调用addNativeLibraries()函数5添加工程libs目录下的Native库(通过android NDK编译生成的sobin文件),6最后调用sealApk()关闭apk文件。

第六步:对apk文件进行签名。

【输入】未签名的.apk文件

【工具】jarsigner

【输出】签名的.apk文件

android的应用程序需要签名才能在android设备上安装,签名apk文件有两种情况:一种是在调试程序时进行签名,使用eclipse开发android程序时,在编译调试程序时会自己使用一个debug.keystoreapk进行签名;另一种是打包发布时对程序进行签名,这种情况下需要提供一个符合android开发文档中要求的签名文件。签名的方法也分两种:一种是使用jdk中提供的jarsigner工具签名;另一种是使用android源码中提供的signapk工具,它的代码位于android系统源码build\tools\signapk目录下。

 

第七步:对签名后的apk文件进行对齐处理。

【输入】签名后的.apk文件

【工具】zipalign工具

【输出】对齐后的.apk文件

这一步需要使用的工具为zipalign,它位于android-sdk\tools目录,源码位于android系统源码的build\tools\zipalign目录,它的主要工作是将spk包进行对齐处理,使spk包中的所有资源文件距离文件起始偏移为4字节整数倍,这样通过内存映射访问apk文件时速度会更快,验证apk文件是否对齐过的工作由ZipAlign.cpp文件的verify()函数完成,处理对齐的工作则由process()函数完成。

 

图例:


 

 

 

Apk的安装

Apk安装关键对象PackageManagerService:

这个服务负责扫描系统中特定的目录,找到里面的应用程序文件,即以Apk为后缀的文件,然后对这些文件进解析,得到应用程序的相关信息,完成应用程序的安装过程。

其实就是解析析应用程序配置文件AndroidManifest.xml的过程,并从里面得到得到应用程序的相关信息,例如得到应用程序的组件ActivityServiceBroadcast ReceiverContent Provider等信息,有了这些信息后,通过ActivityManagerService这个服务,我们就可以在系统中正常地使用这些应用程序了。

流程概述

1、在SystemServer中利用JNI启动相关硬件服务

2、 在JNI中执行runtime

3、 ServerThread中启动PackageManagerServiceActivityManagerService等服务。

4、 PackageManagerService扫描获得APK文件并解析安装

5、 将解析获得的数据存储到PackageManagerService

6、从PackageManagerService中获取图标并展示

具体流程:

第一步:在SystemServer中利用JNI启动相关硬件服务

Zygote进程启动SystemServerJNIinit()初始化方法,初始化SurfaceFlingerSensorServiceAudioFlingerMediaPlayerServiceCameraServiceAudioPolicyService这几个服务。

第二步:在JNI中执行runtime

JNI的出事华中通过系统全局唯一的AndroidRuntime实例变量runtimecallStatic来调用SystemServerinit2函数了。

第三步:在ServerThread中启动PackageManagerService和ActivityManagerService等服务

init2中创建一个ServerThread线程。在这个线程中启动PackageManagerService服务和ActivityManagerService等其他服务。将这些服务加入到ServiceManager中。而ServiceManagerAndroid系统Binder进程间通信机制的守护进程。

第四步:PackageManagerService扫描获得APK文件并解析安装

PackageManagerService类的构造函数中开始执行安装应用程序的过程。

在安装过程中:

1调用scanDirLI函数来扫描移动设备上的下面这五个目录中的Apk文件: /system/framework /system/app /vendor/app/data/app /data/app-private

2将以Apk作为后缀名的文件调用scanPackageLI函数来进行解析和安装。

第五步:将解析获得的数据存储到PackageManagerService中

Apk文件创建一个PackageParser实例,接着调用这个实例的parsePackage函数来对这个Apk文件进行解析,同时调用另外一个版本的scanPackageLI函数把来解析后得到的应用程序信息packageproviderservicereceiveractivity等信息保存在PackageManagerService服务中。  每一个Apk文件都是一个归档文件,它里面包含了Android应用程序的配置文件AndroidManifest.xml,这里主要就是要对这个配置文件就行解析了,从Apk归档文件中得到这个配置文件。

第六步:从PackageManagerService中获取图标并展示

Android系统通过Home应用程序LauncherPackageManagerService服务中把这些安装好的应用程序取出来,并以友好的方式在桌面上展现出来,例如以快捷图标的形式。

 

从开机到应用的启动过程

开机流程概述


Zygote是一个虚拟器进程,正如我们在前一个步骤所说的在系统引导的时候启动。Zygote预加载以及初始化核心库类。通常,这些核心类一般是只读的,也是Android SDK或者核心框架的一部分。在Java虚拟机中,每一个实例都有它自己的核心库类文件和堆对象的拷贝。为了克服Android系统为每一个应用启动不同的Dalvik虚拟机实例,会消耗大量的内存以及时间问题,Android系统创造了”Zygote”,让Dalvik虚拟机共享代码、低内存占用以及最小的启动时间成为可能。

 

开机具体流程

第一步:加载引导程序到ram

当电源按下,引导芯片代码开始从预定义的地方(固化在ROM)开始执行。加载引导程序到RAM,然后执行。

第二步:执行引导程序

引导程序分两个阶段执行。第一个阶段,检测外部的RAM以及加载对第二阶段有用的程序;第二阶段,引导程序设置网络、内存等等。这些对于运行内核是必要的,为了达到特殊的目标,引导程序可以根据配置参数或者输入数据设置内核。

第三步:完成内核的系统设置

Android内核与桌面linux内核启动的方式差不多。内核启动时,设置缓存、被保护存储器、计划列表,加载驱动。当内核完成系统设置,它首先在系统文件中寻找”init”文件,然后启动root进程或者系统的第一个进程。

第五步:执行init进程(即root进程)

init进程有两个责任,一是挂载目录,比如/sys、/dev、/proc,二是运行init.rc脚本。

对于init.rc文件,Android中有特定的格式以及规则。在Android中,我们叫做Android初始化语言。
Android初始化语言由四大类型的声明组成,即Actions(动作)、Commands(命令)、Services(服务)、以及Options(选项)。

Action(动作):动作是以命令流程命名的,有一个触发器决定动作是否发生。

Service(服务):服务是init进程启动的程序、当服务退出时init进程会视情况重启服务。

Options(选项):选项是对服务的描述。它们影响init进程如何以及何时启动服务。
咱们来看看默认的init.rc文件。这里我只列出了主要的事件以及服务。

在这个阶段你可以在设备的屏幕上看到“Android”logo了。

第六步:加载Zygote进程

1)       加载ZygoteInit

2)       registerZygoteSocket()为zygote命令连接注册一个服务器套接字。

3)       preloadClassed “preloaded-classes”是一个简单的包含一系列需要预加载类的文本文件,你可以在<Android Source>/frameworks/base找到“preloaded-classes”文件。

4)       preloadResources() preloadResources也意味着本地主题、布局以及android.R文件中包含的所有东西都会用这个方法加载。

 

第七步:启动系统服务

运行环境请求Zygote运行系统服务(系统服务同时使用native以及java编写,系统服务可以认为是一个进程)。

核心服务:启动电源管理器;创建Activity管理器;启动电话注册;启动包管理器设置Activity管理服务为系统进程启动上下文管理器;启动系统Context Providers;启动电池服务;启动定时管理器;启动传感服务;启动窗口管理器;启动蓝牙服务;启动挂载服务。

其他服务:启动状态栏服务;启动硬件服务;启动网络状态服务;启动网络连接服务;启动通知管理器;启动设备存储监视服务;启动定位管理器;启动搜索服务;启动剪切板服务;启动登记服务;启动壁纸服务;启动音频服务;启动耳机监听;启动AdbSettingsObserver(处理adb命令)。

 

第八步:发送开机启动广播

一旦系统服务在内存中跑起来了,Android就完成了引导过程。在这个时候“ACTION_BOOT_COMPLETED”开机启动广播就会发出去。

 

应用启动流程概述

概述1

1、安卓系统的Launcher通过Binder进程间通信机制通知ActivityManagerService,它要启动一个Activity

2、Launcher通过Binder进程间通信机制通知ActivityManagerService,它要启动一个Activity

3、Launcher通过Binder进程间通信机制通知ActivityManagerService,它已经准备就绪进入Paused状态,于是ActivityManagerService就创建一个新的进程,用来启动一个ActivityThread实例,即将要启动的Activity就是在这个ActivityThread实例中运行;

4、ActivityThread通过Binder进程间通信机制将一个ApplicationThread类型的Binder对象传递给ActivityManagerService,以便以后ActivityManagerService能够通过这个Binder对象和它进行通信;

5、ActivityManagerService通过Binder进程间通信机制通知ActivityThread,现在一切准备就绪,它可以真正执行Activity的启动操作了。

概述2

1、 Launcher 接收到点击事件,获取应用的信息,向 SystemServer(ActivityManagerService 简称AMS 运行在里面) 发起启动应用的请求。

2、 SystemServer(AMS) 请求 Launcher Pause Launcher 需要保存状态进入后台)

3、 Launcher Pause SystemServer(AMS) 发送 Pause 完毕

4、 SystemServer(AMS) Zygote 请求启动一个新进程(calculator)

5、 Zygote fork 出新进程(calculator) , 在新进程中执行 ActivityThread 类的 main 方法

6、 calculator SystemServer(AMS) 请求 attach AMS

7、 SystemServer(AMS) 请求 calculator launch

8、 calculator 调用 onCreate onResume 回调

9、 calculator 界面显示自屏幕上(还需细分)

来自两篇不同的博客,所以对比着看。

 

 

 

 

 

 

 

概述2的具体流程

第一步:Launcher 接收到点击事件向AMS发起启动应用的请求。

1、 Launcher 进程启动的调用栈:ZygoteInit.main ->ActivityThread.main->Looper.loop(进入消息循环)

2、 消息循环中收到系统分发过来的消息,回调 onClick 去启动 Activity

3、 通过ActivityManagerProxy RPC 将请求发送给 AMS。

第二步:SystemServer(AMS) 请求 Launcher Pause

下面的ST是在 ApplicationThreadProxy 的 schedulePauseActivity 函数打印的调用栈。

07-29 07:06:11.922  4151  4183 D zhibinw : java.lang.RuntimeException: ApplicationThreadProxy-schedulePauseActivity
07-29 07:06:11.922  4151  4183 D zhibinw :  at android.app.ApplicationThreadProxy.schedulePauseActivity(ApplicationThreadNative.java:699)
07-29 07:06:11.922  4151  4183 D zhibinw :  at com.android.server.am.ActivityStack.startPausingLocked(ActivityStack.java:842)
07-29 07:06:11.922  4151  4183 D zhibinw :  at com.android.server.am.ActivityStackSupervisor.pauseBackStacks(ActivityStackSupervisor.java:680)
07-29 07:06:11.922  4151  4183 D zhibinw :  at com.android.server.am.ActivityStack.resumeTopActivityInnerLocked(ActivityStack.java:1638)
07-29 07:06:11.922  4151  4183 D zhibinw :  at com.android.server.am.ActivityStack.resumeTopActivityLocked(ActivityStack.java:1477)
07-29 07:06:11.922  4151  4183 D zhibinw :  at com.android.server.am.ActivityStackSupervisor.resumeTopActivitiesLocked(ActivityStackSupervisor.java:2520)
07-29 07:06:11.922  4151  4183 D zhibinw :  at com.android.server.am.ActivityStack.startActivityLocked(ActivityStack.java:2125)
07-29 07:06:11.922  4151  4183 D zhibinw :  at com.android.server.am.ActivityStackSupervisor.startActivityUncheckedLocked(ActivityStackSupervisor.java:2258)
07-29 07:06:11.922  4151  4183 D zhibinw :  at com.android.server.am.ActivityStackSupervisor.startActivityLocked(ActivityStackSupervisor.java:1560)
07-29 07:06:11.922  4151  4183 D zhibinw :  at com.android.server.am.ActivityStackSupervisor.startActivityMayWait(ActivityStackSupervisor.java:994)
07-29 07:06:11.922  4151  4183 D zhibinw :  at com.android.server.am.ActivityManagerService.startActivityAsUser(ActivityManagerService.java:3415)
07-29 07:06:11.922  4151  4183 D zhibinw :  at com.android.server.am.ActivityManagerService.startActivity(ActivityManagerService.java:3402)
07-29 07:06:11.922  4151  4183 D zhibinw :  at android.app.ActivityManagerNative.onTransact(ActivityManagerNative.java:140)
07-29 07:06:11.922  4151  4183 D zhibinw :  at com.android.server.am.ActivityManagerService.onTransact(ActivityManagerService.java:2223)
07-29 07:06:11.922  4151  4183 D zhibinw :  at android.os.Binder.execTransact(Binder.java:446)

这个调用栈正好衔接上面的调用栈,上面是从 Launcher 通过 ActivityManagerProxy RPC 到 SystemServer(AMS) ,这里刚好 RPC 切换到 SystemServer(AMS) 进程。通过一系列调用 SystemServer(AMS)进程向 Launcher 发送 pause 的请求,同样是通过 RPC. 这一来一回,涉及到app 进程和 SystemServer 的交互,涉及到 ActivityManagerNative, ActivityManagerService,ActivityManagerProxy, ApplicationThreadNative,ApplicationThread,ApplicationThreadProxy.一张图来展示它们的关系, 如下:


 

第三步:Launcher Pause ,向 SystemServer(AMS) 发送 Pause 完毕

紧接着,Launcher 会回复 SystemServer(AMS) , Pause 完毕:

 

第四步: SystemServer(AMS) 向 Zygote 请求启动一个新进程(calculator)

然后调到了 SystemServer(AMS) 的 activityPaused,接下来 AMS 尝试去启动 calculator 的界面,发现没有,所以向 Zygote 请求创建一个新的进程。Zygote 存在的目的就是去创建新的进程, SystemServer 通过 socket 和 Zygote 进行通讯。SystemServer 向 Zygote 发送创建新进程的请求,并获取pid 和 usingWrapper

第五步: Zygote fork 出新进程(calculator) , 在新进程中执行ActivityThread 类的 main 方法

从Zygote 的 main 函数可以看出, Zygote 的作用:一是 fork出 SystemServer , 然后进入循环,读取 socket 来的消息,响应 fork 新进程的请求。

Zygote fork 出新进程,分别从子进程和父进程返回。

父进程将结果返回给 SystemServer ,然后继续自己的 loop, 而子进程进入新的入口 ActivityThread。

ActivityThread 是 Application相关的最重要的一个类了,但是名字起的不好,它叫Thread ,但是不是一个 Thread, 它也不局限在 Activity 上。

ActivityThread app 进程运行的入口和框架,个人觉得,看懂了这个类,就看懂了 Android app 框架的设计。它负责 app 与 system_server 交互,负责 app 侧 activity,service,broadcast,provider 管理。

 

第六步:calculator 向 SystemServer(AMS) 请求 attach 到 AMS

新进程启动后的第一件事就是上报(attach)到 SystemServer(AMS) ,使得 SystemServer(AMS) 可以统一管理调度。

第七步:SystemServer(AMS) 请求 calculator launch

SystemServer(AMS) 调用scheduleLaunchActivity 通过IPC 传递到 ActivityThread 的 scheduleLaunchActivity,在 ActivityThread 里面它用 Message 的方式发送自己主线程的Handler 来异步处理。

ActivityThread 作为app入口框架是怎么做的:1.建立消息队列 2.与AMS建立起关联 3.进入循环等待消息/处理消息。 也就是说,attach AMS 之后,app 主线程里接下来都是在异步的方式处理消息,

 

第八步:calculator 调用 onCreate , onResume 回调

 

第九步:calculator 界面显示自屏幕上

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值