Android6.0 Framework分析——应用程序APP的安装过程

应用程序的安装是通过包管理服务PackageManagerService完成的,常见的安装方式有以下几种:

① 内置APP随着系统启动PMS而安装。

② 使用adb install命令安装。

③ 通过系统内置的PackageInstaller应用安装。

④ 在一些手机厂商内置的应用商店下载,然后静默安装。

 

分析源码之后,会发现,其实只有两种方式,

一是系统内置应用通过PackageManagerService使用scanDirLi扫描指定目录下的apk安装。

二是第三方apk通过PackageManager直接或者间接的调用PMS的installPackageAsUser接口安装。

 

安装位置有两种:内置存储器和SD卡(Android6.0需要将SD卡转换为内置存储器才行)。

下文将介绍系统应用扫描安装、adb安装到内部存储器、apk安装到SD卡等情况的安装流程。

首先,我们看一下PackageManager的类关系:

Android6.0 Framework分析——应用程序APP的安装过程_第1张图片

PackageManagerService运行在system进程,为使其他进程使用,用到了binder通信,提供PackageManager接口供调用。

然后, 我们看一下系统APP的安装,之前说到系统APP安装是在系统启动PMS的时候,所以我们从SystemServer启动PMS开始看,下面是大概时序图
Android6.0 Framework分析——应用程序APP的安装过程_第2张图片

step2~step10, SystemServer在启动PMS之前,先启动了Installer这个SystemService,Installer新建一个InstallerConnection对象与installd的一个连接,通过socket通信,PMS每次执行安装、dexoat、卸载等操作时,需要调用Installer接口,然后Installer将封装后的命令通过socket发送给installd执行。

step17, 指定目录的路径传递给scanDirLi。

step18, 对目录下的apk文件逐个调用scanPackageLI方法,进行扫描解析。

step19, apk的解析是通过scanPackageLI新建的PackageParser对象完成的。

step20~step26, 主要是对AndroidManifest.xml文件的解析。

step27, 对签名文件的解析。

step28~step41, apk的安装,包含数据目录的创建/data/data/,apk的dexopt优化,安装之后将apk的信息记录到packages.xml、packages.list;

 

接下来,简介adb安装apk到内置存储器的过程:

Android6.0 Framework分析——应用程序APP的安装过程_第3张图片

adb安装apk的主要过程如下:

1. 首先 apk会被push到手机的/data/local/tmp/目录(如果安装到sd卡,则会push到/sdcard/tmp/)。

2. 执行pm命令,调用PMS的installPackageAsUser接口,工作转移到PMS中。

3. 将apk的安装任务(HanderParams)交给工作线程PackageHandler,第三方apk的安装工作都是由PackageHandler完成的,PackageHandler的初始化是在PMS的构造方法中,准备将apk宝贝到/data/app/下,发送INIT_COPY消息。

4. INIT_COPY主要工作是连接DefaultContainerService服务,将安装任务(InstallParams)加到mPendingInstalls安装列表,等待服务连接成功。

5. 服务连接成功后,发送MCS_BOUND消息,取出安装任务(InstallParams),开始拷贝,新建安装参数(InstallArgs),拷贝时,是先新建一个临时目录,copy成功之后,将临时目录改成包名-的形式

6. 拷贝成功后,新建一个线程,去解析apk执行step20类似的动作,同时工作线程返回去执行下一个安装任务,如果没有安装任务了,就断开之前连接的服务。

 

最后,看一下通过PackageInstaller将apk安装到SD卡的过程:

Android6.0 Framework分析——应用程序APP的安装过程_第4张图片

从图中流程可以看出,与刚才介绍的adb将apk安装到内部存储器的流程是差不多的(包括apk移动操作),只是安装位置不一样,安装参数(InstallArgs)的实现不一样。

Android6.0 Framework分析——应用程序APP的安装过程_第5张图片

 

MeasureParams: 计算APP占用存储空间时使用。

InstallParams: apk安装时使用。

FileInstallArgs:apk安装到内部存储器时使用。

AsecInstallArgs:apk安装到SD卡时使用或者安装FORWARDLOCK类型的apk。

MoveInstallArgs:apk从内部存储器移动到SD卡或者SD卡移动到内部存储器时使用。

InstallParams的handleStartCopy根据条件新建不同的InstallArgs对象:

 

    private InstallArgs createInstallArgs(InstallParams params) {
        if (params.move != null) {
            return new MoveInstallArgs(params);
        } else if (installOnExternalAsec(params.installFlags) || params.isForwardLocked()) {
            return new AsecInstallArgs(params);
        } else {
            return new FileInstallArgs(params);
        }
    }


好了,说到这里了,apk的更新与卸载,可以参照流程,继续学习。

 

 

 

再介绍一下installd进程,installd是个本地进程,代码在frameworks/native/cmds/installd目录,启动是在init进程中,

 

service installd /system/bin/installd
    class main
    socket installd stream 600 system system


直接看installd.cpp的main函数,

 

 

int main(const int argc __unused, char *argv[]) {
    char buf[BUFFER_MAX];
    struct sockaddr addr;
    socklen_t alen;
    int lsocket, s;
    int selinux_enabled = (is_selinux_enabled() > 0);

    setenv("ANDROID_LOG_TAGS", "*:v", 1);
    android::base::InitLogging(argv);

    ALOGI("installd firing up\n");

    union selinux_callback cb;
    cb.func_log = log_callback;
    selinux_set_callback(SELINUX_CB_LOG, cb);

    if (initialize_globals() < 0) { //初始化几个路径相关的全局变量
        ALOGE("Could not initialize globals; exiting.\n");
        exit(1);
    }

    if (initialize_directories() < 0) { //创建目录
        ALOGE("Could not create directories; exiting.\n");
        exit(1);
    }

    if (selinux_enabled && selinux_status_open(true) < 0) {
        ALOGE("Could not open selinux status; exiting.\n");
        exit(1);
    }

    lsocket = android_get_control_socket(SOCKET_PATH);//获得socket,"installd"
    if (lsocket < 0) {
        ALOGE("Failed to get socket from environment: %s\n", strerror(errno));
        exit(1);
    }
    if (listen(lsocket, 5)) { //开始监听socket
        ALOGE("Listen on socket failed: %s\n", strerror(errno));
        exit(1);
    }
    fcntl(lsocket, F_SETFD, FD_CLOEXEC);

    for (;;) { //进入循环
        alen = sizeof(addr);
        s = accept(lsocket, &addr, &alen);//收到InstallerConnection发送的数据
        if (s < 0) {
            ALOGE("Accept failed: %s\n", strerror(errno));
            continue;
        }
        fcntl(s, F_SETFD, FD_CLOEXEC);

        ALOGI("new connection\n");
        for (;;) {
            unsigned short count;
            if (readx(s, &count, sizeof(count))) { //读取数据的长度
                ALOGE("failed to read size\n");
                break;
            }
            if ((count < 1) || (count >= BUFFER_MAX)) {
                ALOGE("invalid size %d\n", count);
                break;
            }
            if (readx(s, buf, count)) {//读取数据的内容
                ALOGE("failed to read command\n");
                break;
            }
            buf[count] = 0;
            if (selinux_enabled && selinux_status_updated() > 0) {
                selinux_android_seapp_context_reload();
            }
            if (execute(s, buf)) break; //解析命令,与cmds数组定义的命令匹配
        }
        ALOGI("closing connection\n");
        close(s);
    }

 

struct cmdinfo cmds[] = {
    { "ping",                 0, do_ping },//测试socket是否连接成功
    { "install",              5, do_install },//创建app数据目录,如/data/data/vmdl.tmp
    { "dexopt",               9, do_dexopt },//对apk优化,调用的是dex2oat程序
    { "markbootcomplete",     1, do_mark_boot_complete },//好像没用到
    { "movedex",              3, do_move_dex },//classes.dex文件移动
    { "rmdex",                2, do_rm_dex },//classed.dex删除
    { "remove",               3, do_remove },//apk卸载
    { "rename",               2, do_rename },//目录重命名
    { "fixuid",               4, do_fixuid },//uid变动
    { "freecache",            2, do_free_cache },//释放app缓存空间
    { "rmcache",              3, do_rm_cache },//删除cache目录内容
    { "rmcodecache",          3, do_rm_code_cache },//删除code_cache目录内容
    { "getsize",              8, do_get_size },//获得指定app的大小
    { "rmuserdata",           3, do_rm_user_data },//删除用户数据
    { "cpcompleteapp",        6, do_cp_complete_app },
    { "movefiles",            0, do_movefiles },
    { "linklib",              4, do_linklib },
    { "mkuserdata",           5, do_mk_user_data },
    { "mkuserconfig",         1, do_mk_user_config },
    { "rmuser",               2, do_rm_user },
    { "idmap",                3, do_idmap },
    { "restorecondata",       4, do_restorecon_data },
    { "createoatdir",         2, do_create_oat_dir },
    { "rmpackagedir",         1, do_rm_package_dir },
    { "linkfile",             3, do_link_file }
};


struct cmdinfo的原型:

 

 

struct cmdinfo {
    const char *name;
    unsigned numargs;
    int (*func)(char **arg, char reply[REPLY_MAX]);
};

 

 

欢迎关注"东哥笔迹"

 

 

 

 

未完待续,有不对的地方,请指正。

你可能感兴趣的:(Android,Framework分析)