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看看安装到底是怎么一回事。