💎一站式轻松地调用各大LLM模型接口,支持GPT4、智谱、星火、月之暗面及文生图 广告
pm_command代码如下: **commandline.c** ~~~ static int pm_command(transport_type transport,char* serial, int argc, char** argv) { charbuf[4096]; snprintf(buf,sizeof(buf), "shell:pm"); ......//准备参数 //发送"shell:pm install 参数"给手机端的adbd send_shellcommand(transport, serial, buf); return0; } ~~~ 手机端的adbd在收到客户端发来的shellpm命令时会启动一个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/bincom.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程序。 >[info] **注意**:Android系统中常用的monkeytest、pm、am等(这些都是脚本文件)都是以这种方式启动的,所以严格地说,app_process才是Android Java进程的老祖宗。 下面来分析pm.java,app_process执行的就是它定义的main函数,它相当于Java进程的入口函数,其代码如下: **pm.java** ~~~ public static void main(String[] args) { newPm().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** ~~~ private void runInstall() { intinstallFlags = 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看看安装到底是怎么一回事。