添加链接
link之家
链接快照平台
  • 输入网页链接,自动生成快照
  • 标签化管理网页链接

1. Apk安装

常见的apk安装方式有三种:

  1. 系统自带的应用和厂商预装的应用. 没错, 系统自带的应用其实也是apk, 其安装是在系统首次启动时完成的. 这也就是为什么root后可以卸载系统自带应用.没有安装界面.
  2. 通过存储介质安装. 最常见的就是通过sd卡放置apk或者网上下载apk方式安装.通过 packageinstaller.apk来处理安装及卸载的过程的界面
  3. adb命令安装. 这应该是开发者最熟悉的安装方式了, 包括 adb install adb pm install .没有安装界面.

三种安装方式, 在安装apk时最终都是同一套流程, 即处理apk文件的流程. 安装过程可以归结为以下几个步骤:

  1. 将apk文件拷贝到指定目录下. 系统应用是在 /system/app , 第三方应用在 /data/app 下.
  2. 解压apk, 拷贝文件. 创建UID, 创建 /data/data/${package_name} 目录, 设置权限. 这个就是应用的数据目录.
  3. 从apk中提取dex, 放到 /data/dalvik-cache 目录.
  4. 解析 AndroidManifest.xml 文件, 提取信息添加到 PMS 中, 更新PMS中相应的数据结构. 具体是, 将提取到的包信息更新到 /data/system/packages.list /data/system/packages.xml .
  5. 发送广播 Intent.ACTION_PACKAGE_ADDED 或者 Intent.ACTION_PACKAGE_REPLACED . 从名字可以判断分别对应全新安装和覆盖安装.

Android中每个app都要一个 userId(UID) 的原因:Android在系统设计上把每个应用当做Linux系统上的一个用户对待,这样就可以利用已有的Linux用户管理机制来设计Android应用,比如应用目录/应用权限/应用进程管理等.

  • 系统自带的以及厂商预装的app, 在手机首次启动时, 会通过扫描 /system/app /system/framework /vendor/app 等目录下面的APK文件, 完成安装. 原生系统没有 vendor (供应商)目录.
  • 至于通过 adb push 的方式, 如果root过, 完全可以推送到系统目录, 以系统应用的方式进行安装. 系统应用的好处是系统在启动的时候就会将apk进行解压复制, 坏处是没办法热更新等. 推送到一般目录, 则可以使用系统命令 /bin/pm 安装apk文件. pm 就是一个可执行文件版的 PackageManager . 最终调用 PackageManager.installPackage() -> PackageManagerService.installPacakge() 进行安装. 顺便一提, 具有 INSTALL_PACKAGES 权限就可以自己调用这个方法进行apk安装.

扫描apk安装, 主要是 PackageManagerService 进行安装包扫描和解析工作. 信息解析完毕后存在特定数据结构中( PackageParser.Package ), 此后需要进行信息同步工作. 这是因为, 扫描到的APK可能是已经更名的包/disable的包/需要升级的包/已经安装但签名冲突的包/替换了系统包的非系统包等情况, 需要处理这些情况, 保证最终信息正确.
如果包需要进行 Rename 或者 Update , 则需要签名比较.
而使用 adb shell pm 安装略有不同, 是由 com.android.commands.pm.Pm 中的 runInstall 来安装的( adb install 最终也是调用的 shell pm ).

核心函数scanPackageDirtyLI

系统最初调用 installPackageAsUser 检查是否有安装权限, 安装APK的整个过程在 PackageHandler 中进行, 主要分为 拷贝APK(检查是否有足够空间)->扫描APK->安装后处理(主要是发送广播信息), 其中最关键的一步就是扫描APK, 由函数 scanPackageLI 完成, 该函数里面调用 scanPackageDirtyLI .
scanPackageDirtyLI() 源码位于 frameworks/base/services/core/java/com/android/server/pm/PackageManagerService.java 中(基于7.0源码):
参考http://blog.hjhjw1991.com/android/2018/01/02/Apk%E5%AE%89%E8%A3%85%E5%8D%B8%E8%BD%BD%E5%8E%9F%E7%90%86/

安装后的目录结构
目录 含义
/system/app 系统自带的应用程序,获得 root 权限才能删除
/data/app 第三方应用apk文件.安装时把apk文件复制到此目录
/data/anr 存放anr信息(/data/anr/traces.txt用于存放app ANR信息)
/data/data 应用程序数据
/data/data/${package_name} 特定应用程序数据目录
/data/data/${package_name}/cache 临时文件,系统会自动清理
/data/data/${package_name}/databases 数据库
/data/data/${package_name}/files 一般文件
/data/data/${package_name}/shared_pres SharedPreference
/data/data/${package_name}/lib so文件
/data/dalvik-cache 存放odex文件.将apk中的dex文件安装到dalvik-cache目录下(dex文件是dalvik虚拟机的可执行文件,ART模式的可执行文件格式为.aot,启动ART时,系统会执行dex文件转换至aot文件)
/data/system/packages.list 类似于Window的注册表,该文件是解析apk时由writeLP()创建的。记录了系统的permissons,以及解析apk的AndroidManifest获取的应用name,codePath,flag,ts,version,userid等信息。解析完apk后将更新信息写入这个文件并保存到flash,下次开机的时候直接从里面读取相关信息并添加到内存相关列表中.当有apk升级,安装或删除时会更新这个文件。
/data/system/packages.xml 指定应用的默认存储位置/data/data/com.xx.xx/package.xml中包含了该应用申请的权限,签名和代码所在的位置等信息系,并且两者都有同一个userld.
/data/user/0 软链接,指向/data/data
/data/user_de/0/${package_name} 设备存储保护区,在快速启动模式可以访问这个文件夹
/proc/cpuinfo cpu信息
/proc/smaps 内存占用信息
/sdcard 软链接,最终指向/storage/emulated/0【跟Android版本和ROM版本有关】
/storage/emulated/0 外部存储的根目录
/storage/emulated/0/Android/data/${package_name} 应用的额外数据
/system/app 系统应用apk文件
/system/lib 系统应用so库

/data/data/包名 目录下,每个app都有自己的目录,目录名就是应用程序在 AndroidManifest.xml 文件中定义的包。每个应用程序的代码,对自己的目录是有绝对的控制权限的。在每个目录下,一般有如下几个子目录(结合上面的表格):

  • databases : 存放数据库
  • cache : 存放缓存数据
  • files : 存放应用程序自己控制的文件
  • lib : 存放使用的包

在第三方app安装后,会创建的目录、文件以及记录的信息:

  1. 拷贝的apk文件,位于 /data/app
  2. 创建的app数据目录 /data/data/${package_name}
  3. 从apk中提取的dex文件,位于 /data/dalvik-cache 目录下
  4. /data/system/packages.list /data/system/packages.xml 中关于app的记录信息

另外,app在运行期间有可能会使用到外部存储目录 /storage/emulated/0/Android/data/${package_name} ,该目录只有在app运行时调用相关函数时才创建,app安装后不会创建的。

2. Apk卸载

卸载是安装的逆过程, 删除在创建过程中三个路径下产生的文件夹 ,以及有可能后面创建的外部存储目录 /storage/emulated/0/Android/data/${package_name}
通过系统来卸载App通常是,点击卸载后,就会发送一个 Intent UninstallerActivity ,在 UninstallerActivity 最后会启动 UninstallAppProgress initView 方法,调用到 ApplicantPackageManger.java deletePackage 方法,通过 Binder 绑定,其实是调用 PMS 中的 deletePackageAsUser 方法, 同样位于 /frameworks/base/services/core/java/com/android/server/pm/PackageManagerService.java
源码参考:http://blog.hjhjw1991.com/android/2018/01/02/Apk%E5%AE%89%E8%A3%85%E5%8D%B8%E8%BD%BD%E5%8E%9F%E7%90%86/

卸载第三方app最后由 deleteInstalledPackageLI() 方法来完成,分两步走:

  1. 第一步删除 /data/data 下面的数据目录,并从PMS的内部数据结构上清除当前卸载的package信息
    1. deleteInstalledPackageLI() –>(表示调用,下同) removePackageDataLI() removePackageDataLI() –> removePackageLI() –>mPackages的 remove() :删除apk。 removePackageLI() –> cleanPackageDataStructuresLILPw() :将package的 providers services receivers activities 等信息去PMS的全局数据结构上移除。
    2. removePackageDataLI() –> removeDataDirsLI() –>installd的 remove() :删除目录 /data/data/${package_name}
    3. removePackageDataLI() –> schedulePackageCleaning() :安排清理动作。向 PackageHandler 发送 START_CLEANING_PACKAGE 消息,PMS会调用 ContainService 的函数去删除 /storage/sdcard0/Android/data /storage/sdcard0/Android/media 下面与 package 相关的文件
    4. removePackageDataLI() –>Settings的 removePackageLPw() :首先从 mPackages 这个 map 中删除 PackageSettings 信息,即删除对应的 Package UID 信息
    5. removePackageDataLI() –> updatePermissionsLPw() :检查 mPermissionTrees mPermissions 两个数组中的权限是否是被删除的 Package 提供,如果有,则删除。
    6. removePackageDataLI() –>Settings的 updateSharedUserPermsLPw() :清除 sharedUser 不用的 gid 信息,防止权限泄露。
    7. removePackageDataLI() –>Settings的 writeLPr() :将修改的信息写到 Package.xml
  2. 第二步就删除code和resource文件
    1. 分别构造 FileInstallArgs AsecInstallArgs 来完成code和resource资源的清除
    2. FileInstallArgs doPostDeleteLI() –> cleanUpResourcesLI() –> cleanUp() :删除code、resource以及library文件
    3. cleanUpResourcesLI() –>installd的 rmdex() :删除存在 /data/dalvik-cache 文件

参考:
https://blog.csdn.net/xinsong1989/article/details/78527439

http://blog.hjhjw1991.com/android/2018/01/02/Apk%E5%AE%89%E8%A3%85%E5%8D%B8%E8%BD%BD%E5%8E%9F%E7%90%86/

https://blog.csdn.net/hanfengzqh/article/details/82790896

apk本质上就是一个zip包1. Apk安装常见的apk安装方式有三种:系统自带的应用和厂商预装的应用. 没错, 系统自带的应用其实也是apk, 其安装是在系统首次启动时完成的. 这也就是为什么root后可以卸载系统自带应用.没有安装界面.通过存储介质安装. 最常见的就是通过sd卡放置apk或者网上下载apk方式安装.通过 packageinstaller.apk来处理安装及卸载的过程的...
Android 与IOS一个比较大的不同就是 文件 夹部分,IOS在 应用的时候会同时 删除 应用所 创建 的所有 文件 文件 夹, Android 不会。 以下是执行这个操作的方法。 首先写一个广播接收器即BroadcastReceiver public class Receiver extends BroadcastReceiver { @Override public void onReceive(
前段时间由于项目的需要,研究了下 Android App 安装 ,这段时间整理了下,写成博客,方便以后查看。 一个手机 App ,经下 安装 、更新、 。 下 就不说了,本篇博客主要研究 安装 、更新和 。 一个apk经过下 下来,有几种 安装 方式? 1.内置 APP 随着系统启动PMS而 安装 。(刷机后一般第一步操作就是这个) 2.使用adb install命令 安装 。(开发人员常用方式)
应用程序在运行的 过程 中如果需要向手机上保存数据,一般是把数据保存在SDcard中的。 大部分应用是直接在SDCard的根 目录 创建 一个 文件 夹,然后把数据保存在该 文件 夹中。 这样当该应用被 后,这些数据还保留在SDCard中,留下了垃圾数据。 如果你想让你的应用被 后,与该应用相关的数据也清除掉,该怎么办呢? 通过Context.getExternalFilesDir()方法
首先我们要清楚总体可以分成如下几种 安装 的情况 * 系统开机的应用 安装 安装 的是系统级别的应用,用户在没有获取到root权限的情况下无法 的应用 * adb 安装 的应用,没有 安装 界面 * 第三方市场下 的应用,此处要分情况,部分是通过电脑的客户端 安装 的没有 安装 的界面,部分是手机上的市场 安装 的,会有 安装 的界面那么我们就对几种情况一一分析它的 安装 流程 ### 开机 安装 1. 首先在开机
作者venshine,源码 App Uninstall,方案监听系统 广播:只能监听到其他应用的 广播,无法监听到自己是否被 。读取系统 log:第三方软件 无法得知。静默 安装 另一个程序,监听自己是否被 :需要 root 权限。Java 线程轮询,监听/data/data/{package-name} 目录 是否存在: app ,进程退出,线程也被销毁。C 进程轮询,监听/data/data/{package-name} 目录 是否存在:目前业界普遍采用的方案。原理从前四种方案可以看到,单纯的 Java 层代码是无法监听自身 的。既然 Java 层无法实现,我们试着使用 C 语言在底层实现。借助 Linux 进程 fork 出来的 C 进程在应用被 后不会被销毁,监听/data/data/{package-name} 目录 是否存在,如果不存在,就证明应用被 了。本程序采用第 5 种解决方案,对其进行优化,通过 linux 中的inotify机制来监听应用的 。实现fork()子进程 创建 监听 文件 初始化 inotify 实例注册监听事件调用 read 函数开始监听 反馈统计场景正常 断网 清除数据(5.0 以上不支持)kill 进程(5.0 以上不支持)插拔 USB 线覆盖 安装 内部存储移到 SD 卡开机监听(官方不推荐)打开浏览器(5.0 以上部分机型无法开启)
安装 应用 目录 结构在PMS启动初始化时,会扫描一下 目录 ,并 安装 对应的应用。每个 目录 下是已 安装 的应用,每个应用的对应 目录 包括apk 文件 ,lib库so 文件 ,以及oat 文件 /system/ app /data/ app /data/ app -asec /data/ app -privatepackages.xml 文件 在/data/system 目录 下,packages.xml保存了系统 安装 的应用相
java.lang.UnsatisfiedLinkError: dlopen failed: "/data/ app /packagename-2/lib/arm/libxxxxxx.so" is 32-bit instead of 64-bit 问题出现后检查libaudiooperate.so的确是32位的so,然后查...
解决Could not load dynamic library 'libcudart.so.10.0'; dlerror: libcudart.so.10.0: cannot open ... 41521