4.4.2 pm分析
pm_command代码如下:
[—>commandline.c:pm_command]
static int pm_command(transport_type transport, char*serial,
int argc, char**argv)
{
char buf[4096];
snprintf(buf, sizeof(buf),"shell:pm");
……//准备参数
//发送"shell:pm install参数"给手机端的adbd
send_shellcommand(transport, serial, buf);
return 0;
}
手机端的adbd在收到客户端发来的shell pm命令时会启动一个shell,然后在其中执行pm。pm是什么?为什么可以在shell下执行?
提示 读者可以通过adb shell登录到自己手机,然后执行pm,看看会发现什么。
pm实际上是一个脚本,其内容如下:
[—>pm]
Script to start"pm"on the device, which has a very rudimentary
shell.
#
base=/system
export CLASSPATH=$base/frameworks/pm.jar
exec app_process$base/bin com.android.commands.pm.Pm"$@"
在编译system.image时,Android.mk中会将该脚本复制到system/bin目录下。从pm脚本的内容来看,它就是通过app_process执行pm.jar包的main函数。在卷I第4章分析Zygote时,已经介绍了app_process是一个Native进程,它通过创建虚拟机启动了Zygote,从而转变为一个Java进程。实际上,app_process还可以通过类似的方法(即先创建Dalvik虚拟机,然后执行某个类的main函数)来转变成其他Java程序。
注意 Android系统中常用的monkeytest、pm、am等(这些都是脚本文件)都是以这种方式启动的,所以严格地说,app_process才是Android Java进程的老祖宗。
下面来分析pm.java, app_process执行的就是它定义的main函数,它相当于Java进程的入口函数,其代码如下:
[—>pm.java]
public static void main(String[]args){
new Pm().run(args);//创建一个Pm对象,并执行它的run函数
}
//直接分析run函数
public void run(String[]args){
boolean validCommand=false;
……
//获取PKMS的binder客户端
mPm=IPackageManager.Stub.asInterface(
ServiceManager.getService("package"));
……
mArgs=args;
String op=args[0];
mNextArg=1;
……//处理其他命令,这里仅考虑install的处理
if("install".equals(op)){
runInstall();
return;
}
……
}
接下来分析pm.java的runInstall函数,代码如下:
[—>pm.java:runInstall]
private void runInstall(){
int installFlags=0;
String installerPackageName=null;
String opt;
while((opt=nextOption())!=null){
if(opt.equals("-l")){
installFlags|=PackageManager.INSTALL_FORWARD_LOCK;
}else if(opt.equals("-r")){
installFlags|=PackageManager.INSTALL_REPLACE_EXISTING;
}else if(opt.equals("-i")){
installerPackageName=nextOptionData();
……//参数解析
}……
}
final Uri apkURI;
final Uri verificationURI;
final String apkFilePath=nextArg();
System.err.println("/tpkg:"+apkFilePath);
if(apkFilePath!=null){
apkURI=Uri.fromFile(new File(apkFilePath));
}……
//获取Verification Package的文件位置
final String verificationFilePath=nextArg();
if(verificationFilePath!=null){
verificationURI=Uri.fromFile(new File(verificationFilePath));
}else{
verificationURI=null;
}
//创建PackageInstallObserver,用于接收PKMS的安装结果
PackageInstallObserver obs=new PackageInstallObserver();
try{
//①调用PKMS的installPackageWithVerification完成安装
mPm.installPackageWithVerification(apkURI, obs,
installFlags, installerPackageName,
verificationURI, null);
synchronized(obs){
while(!obs.finished){
try{
obs.wait();//等待安装结果
}……
}
if(obs.result==PackageManager.INSTALL_SUCCEEDED){
System.out.println("Success");//安装成功,打印Success
}……//安装失败,打印失败原因
}……
}
Pm解析参数后,最终通过PKMS的Binder客户端调用installPackageWithVerification以完成后续的安装工作,所以,下面进入PKMS看看安装到底是怎么一回事。