这篇文章准备用来回答:dex2oat从哪被调用的?从什么时候被调用的?
什么是PackageManagerService
- PackageManagerService是Android系统的核心服务之一,负责系统中Package的管理,应用程序的安装、卸载、信息查询等。开机时由systemServer启动此服务
- 源码位置:
/frameworks/base/services/core/java/com/android/server/pm/PackageManagerService.java
从程序安装说起
基础概述
- APK有多种安装方式,大致可以分为:
1.无界面安装:使用adb命令安装;通过网络下载的的应用
2.有界面安装:从SD卡点击安装包安装;通过第三方应用商店安装
- 应用安装涉及到的目录:
1./system/app
:系统自带的应用程序,获得adb root权限才能删除
2./data/app
:用户程序安装的目录。安装时把apk文件复制到此目录
3./data/data
:存放应用程序的数据
4./data/dalvik-cache
:将apk中的dex文件安装到dalvik-cache目录下(oat文件存在的目录)
5./data/system
:该目录下的packages.xml
文件,类似于Windows的注册表,这个文件是在解析apk时由writeLP()
创建的,里面记录了系统的permissions,以及每个apk的name,codePath,flags,ts,version,uesrid等信息,这些信息主要通apk的AndroidManifest.xml
解析获取,解析完apk后将更新信息写入这个文件并保存到flash,下次开机直接从里面读取相关信息添加到内存相关列表中。当有apk升级,安装或删除时会更新这个文件
- 安装的总体过程
1.拷贝apk文件到指定目录
/data/app目录是用户有权限访问的目录,在安装apk的时候会自动选择该目录存放用户安装的文件,而系统出厂的apk文件则被放到了/system
分区下,包括/system/app
,/system/vendor/app
,以及 /system/priv-app
等等,该分区只有Root权限的用户才能访问,这也就是为什么在没有Root手机之前,我们无法删除系统出厂的app的原因
2.解压apk,拷贝文件,创建应用的数据目录
为了加快app的启动速度,apk在安装的时候,会首先将app的可执行文件(dex)拷贝到/data/dalvik-cache
目录,缓存起来。然后,在/data/data/
目录下创建应用程序的数据目录(以应用的包名命名),存放应用的相关数据,如数据库、xml文件、cache、二进制的so动态库等等。
3.解析apk的AndroidManifinest.xml
文件
系统在安装apk的过程中,会解析apk的AndroidManifinest.xml
文件,提取出这个apk的重要信息写入到packages.xml
文件中,这些信息包括:权限、应用包名、APK的安装位置、版本、userID
等等。
4.显示快捷方式
这些应用程序只是相当于在PackageManagerService
服务注册好了,如果我们想要在Android桌面上看到这些应用程序,还需要有一个Home应用程序,负责从PackageManagerService
服务中把这些安装好的应用程序取出来,并以友好的方式在桌面上展现出来,例如以快捷图标的形式。在Android系统中,负责把系统中已经安装的应用程序在桌面中展现出来的Home应用程序就是Launcher
,它由ActivityManagerService
启动的。
1-3是由PackageServiceManager
完成的;4是由Launcher
完成的。
安装过程的源码分析(adb方式)
adb install
有多个参数,现在只考虑adb install ***.apk
源码位置:/system/core/adb/commanline.cpp
分析commanline.cpp
int adb_commandline(int argc, const char **argv) {
...
else if (!strcmp(argv[0], "install")) {
if (argc < 2) return usage();//参数不够的时候提醒,打印help
return install_app(ttype, serial, argc, argv);
}
else if (!strcmp(argv[0], "install-multiple")) {
if (argc < 2) return usage();
return install_multiple_app(ttype, serial, argc, argv);
}
....
}
找到了参数install
,接着调用了install_app
1.install_app
static int install_app(transport_type transport, const char* serial, int argc,
const char** argv)
{//把APK文件复制到手机
//如果安装在手机内部存储,则目标目录为/data/local/tmp(默认)
//安装到SD卡,则目标目录为/sdcard/tmp(参数"-s")
static const char *const DATA_DEST = "/data/local/tmp/%s";
static const char *const SD_DEST = "/sdcard/tmp/%s";
const char* where = DATA_DEST;
for (i = 1; i < argc; i++) {
if (!strcmp(argv[i], "-s")) {
where = SD_DEST;
}
}
...
//取出apk名
const char* apk_file = argv[last_apk];
char apk_dest[PATH_MAX];
//构造apk目的地址
snprintf(apk_dest, sizeof apk_dest, where, get_basename(apk_file));
//将APK文件传输到手机目的地址
int err = do_sync_push(apk_file, apk_dest, 0 /* no show progress */);
if (err) {
goto cleanup_apk;
} else {
argv[last_apk] = apk_dest; /* destination name, not source location */
}
err = pm_command(transport, serial, argc, argv);
总的来说是将APK文件传输到目的手机的tmp目录下,然后调用pm_command进行处理。
2.pm_command
static int pm_command(transport_type transport, const char* serial,
int argc, const char** argv)
{
std::string cmd = "shell:pm";
//根据传进来的参数构造pm命令
while (argc-- > 0) {
cmd += " " + escape_arg(*argv++);
}
return send_shell_command(transport, serial, cmd);
}
根据install_app中传入的参数构造pm命令,然后传到shell中执行。
3.send_shell_command
static int send_shell_command(transport_type transport_type, const char* serial,
const std::string& command) {
int fd;
while (true) {
std::string error;
fd = adb_connect(command, &error);
if (fd >= 0) {
break;
}
fprintf(stderr,"- waiting for device -\n");
adb_sleep_ms(1000);
wait_for_device("wait-for-device", transport_type, serial);
}
read_and_dump(fd);
int rc = adb_close(fd);
if (rc) {
perror("close");
}
return rc;
}
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。