您的位置:首页 > 移动开发

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

2016-08-05 18:00 405 查看
应用程序的安装是通过包管理服务PackageManagerService完成的,常见的安装方式有以下几种:

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

② 使用adb install命令安装。

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

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

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

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

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

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

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

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



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

然后, 我们看一下系统APP的安装,之前说到系统APP安装是在系统启动PMS的时候,所以我们从SystemServer启动PMS开始看,下面是大概时序图



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/<packagename>,apk的dexopt优化,安装之后将apk的信息记录到packages.xml、packages.list;

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



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/<pkgname>下,发送INIT_COPY消息。

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

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

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

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



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



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<sessionid>.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 PMS apk安装