第9章 APK的安装过程

本章分析Package Manager的主要功能之一:APK的安装。安装APK的方法有多种,比较常用的有以下方法:

scanDirLI:系统启动PackageManagerService阶段通过scanDirLI方法完成APK的安装和删除。

adb命令:通过adb push命令将APK文件push到AppDirObserver监控目录,触发扫描安装。通过adb install命令调用pm脚本安装指定的APK。

Google Market:通过Market下载远程APK到本地,使用PackageManager安装。

PackageInstaller. apk:通过系统提供的PackageInstaller.apk安装和卸载其他APK。

后两种方法与前两种方法的机制相似,本章以scanDirLI和adb命令为例分析APK的安装过程。

9.1 通过scanDirLI方法安装APK

在第8章分析PackageManagerService启动过程时,已经对scanDirLI做了简单介绍,该方法会扫描安装在system/framework、system/app、vendor/app、data/app、data/app-private目录下的APK文件。本节承接第8章的内容首先从scanDirLI入手分析APK的安装过程。

scanDirLI定义于PackageManagerService.java中,代码如下:


private void scanDirLI(File dir, int flags, int scanMode, long currentTime)

{

String[]files=dir.list();//APK文件所在目录

……

int i;

for(i=0;i<files.length;i++){//遍历目录下的所有文件

File file=new File(dir, files[i]);

if(!isPackageFilename(files[i])){//忽略非APK文件

continue;

}

/调用scanPackageLI扫描APK文件,扫描结果存入PackageParser.Package/

PackageParser.Package pkg=scanPackageLI(file,

flags|PackageParser.PARSE_MUST_BE_APK, scanMode, currentTime);

/删除安装失败的非系统级APK/

if(pkg==null&&(flags&PackageParser.PARSE_IS_SYSTEM)==0&&

mLastScanError==PackageManager.INSTALL_FAILED_INVALID_APK){

file.delete();

}

}

}


scanDirLI方法做了三部分工作:

1)循环遍历指定目录下的文件,并过滤掉非APK文件。

2)对于APK文件,调用scanPackageLI处理,处理结果存入PackageParser.Package中。

3)处理完成后,删除出错的非系统级APK。非系统级APK由传入的flags参数确定。

当scanDirLI的第二个参数flags设置了以下标记后,第一个参数dir目录下的APK便称为系统级APK。

PackageParser. PARSE_IS_SYSTEM|PackageParser.PARSE_IS_SYSTEM_DIR

默认只有扫描system/framework、system/app、vendor/app三个目录时才会设置系统级APK标记。(flags&PackageParser.PARSE_IS_SYSTEM)==0的作用是判断flags中是否设置PackageParser.PARSE_IS_SYSTEM,如果没有这一项,&运算的结果便是0,即为非系统级APK。

scanDirLI的第一和第三部分工作很好理解,最重要的工作放在第二部分的scanPackageLI中完成。scanPackageLI是一个重载方法,定义于PackageManagerService.java中,用于扫描具体的APK文件,其方法声明如下:


private PackageParser.Package scanPackageLI(File scanFile,

int parseFlags, int scanMode, long currentTime)


它的另一个重载方法的声明如下:


private PackageParser.Package scanPackageLI(PackageParser.Package pkg,

int parseFlags, int scanMode, long currentTime)


注意 本章以scanPackageLI(File,……)的简写形式表示第一个方法,以scanPackageLI(PackageParser.Package,……)表示第二个方法。

scanPackageLI的执行过程分为四个阶段,接下来分析这四个阶段。

9.1.1 创建PackageParser

本节分析scanPackageLI的第一阶段。该阶段的入口是scanPackageLI(File,……)方法,代码如下:


private PackageParser.Package scanPackageLI(File scanFile,

int parseFlags, int scanMode, long currentTime){

String scanPath=scanFile.getPath();//APK文件

/*mDefParseFlags在PackageManagerService启动阶段赋值,如果系

统属性debug.separate_processes设置为“”,则mDefParseFlags

赋值为PackageParser.PARSE_IGNORE_PROCESSES,否则赋值为0/

parseFlags|=mDefParseFlags;//合并parseFlags和mDefParseFlags

PackageParser pp=new PackageParser(scanPath);

/*mSeparateProcesses在PackageManagerService启动阶段赋值,如果

系统属性debug.separate_processes未设置或者设置为“”,则

mSeparateProcesses赋值为null,否则设置为系统属性指定的值/

pp.setSeparateProcesses(mSeparateProcesses);

/*mOnlyCore默认为false,如果系统属性vold.decrypt设置为

*"trigger_restart_min_framework"或者"1",则mOnlyCore会赋值为

ture,该值将决定parsePackage是否只加载核心app,后续步骤再分析/

pp.setOnlyCoreApps(mOnlyCore);

/*用到了mMetrics对象,用于PackageParser解析APK资源的时候选择

对应资源,解析结果存入PackageParser.Package中/

final PackageParser.Package pkg=pp.parsePackage(scanFile,

scanPath, mMetrics, parseFlags);

if(pkg==null){//解析失败后记录失败信息,并跳过这个APK的处理

mLastScanError=pp.getParseError();

return null;

}

……//省略后续步骤


scanPackageLI(File,……)方法在第一阶段中以APK文件为参数创建PackageParser,然后调用PackageParser的parsePackage方法进入第二阶段,解析APK的AndroidManifest.xml文件中包含的各种package信息,并将解析结果存入PackageParser.Package类型的pkg变量。