这篇文章准备用来回答: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;
}

wydong
40 声望5 粉丝

wyd