adb安装应用
应用安装涉及目录: system/app ---------------系统自带的应用程序,获得adb
root权限才能删除data/app ---------------用户程序安装的目录。安装时把
apk文件复制到此目录data/data ---------------存放应用程序的数据data/dalvik-cache--------将apk中的dex文件安装到dalvik-cache目录下(dex文件是dalvik虚拟机的可执行文件)
adb大致有三种方式可以安装应用,分别是
adb
install, adb push 和adb shell pm
install
网上查资料说的adb
install也是使用pm命令,和adb
shell pm install方式相同,但更加简单,所以,这里统一成adb
install方式。
pm命令
使用的是pm命令进行安装,这个pm是什么个东西?
pm位于手机/system/bin/目录下,源码是frameworks/base/cmds/pm,我们看到,pm是一个很简单的shell脚本
# Script
to start "pm" on the device, which has a very rudimentary
shell.
#
base=/system
export
CLASSPATH=$base/framework/pm.jar
exec
app_process $base/bin com.android.commands.pm.Pm
"$@"
CLASSPATH指定了你的程序的位置,com.android.commands.pm.Pm则说明了程序的入口为com.android.commands.pm.Pm,即入口函数main()所在的类,"$@"就是传递给main()函数的参数,只是这里"$@"本身又是个shell传入的参数而已。
执行pm命令其实是通过运行shell脚本frameworks/base/cmds/pm/pm,然后在该脚本中运行app_process命令来启动framework/pm.jar包中的Pm这个java程序的。这个启动过程,有兴趣的同学可以看另一篇>>,这里就不在重复了,接下来,就到com.android.commands.pm.Pm类来处理参数了。
Pm类很简单,具体安装过程是在PackageManagerService中,通过调用PackageManagerService.installPackage()。adb
install xxxx.apk会通过app_process启动Pm程序,将install
xxxx.apk参数传入main()方法中。
//Pm.java
public
static void main(String[] args)
{
new Pm().run(args);
//这里args就是参数列表,如install
xxx.xxx.xxx.apk
}
public
void run() {
…………………………
mArgs = args;
//参数列表
String
op = args[0];
//取第一个参数,也就是pm后面跟着的命令
mNextArg = 1;
//下一个参数的索引
…………………………………………………………..
if ("install".equals(op))
{
runInstall();
return;
}
………………………….
}
private
void runInstall() {
int
installFlags = 0;
String installerPackageName = null;
String opt;
while
((opt=nextOption()) != null) { //
nextOption()取mNextArg当前位置的参数,比如-r
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();
if (installerPackageName == null) {
System.err.println("Error: no value specified for
-i");
showUsage();
return;
}
} else if (opt.equals("-t")) {
installFlags |=
PackageManager.INSTALL_ALLOW_TEST;
} else if (opt.equals("-s")) {
// Override if -s option is specified.
installFlags |= PackageManager.INSTALL_EXTERNAL;
} else if (opt.equals("-f")) {
// Override if -s option is specified.
installFlags |= PackageManager.INSTALL_INTERNAL;
} else {
System.err.println("Error: Unknown option: " +
opt);
showUsage();
return;
}
}
String apkFilePath = nextArg(); //取安装包文件路径
System.err.println("\tpkg: " + apkFilePath);
if
(apkFilePath == null) {
System.err.println("Error: no package
specified");
showUsage();
return;
}
PackageInstallObserver obs = new
PackageInstallObserver();
try
{
mPm.installPackage(Uri.fromFile(new
File(apkFilePath)), obs, installFlags,
installerPackageName);
synchronized (obs)
{
//等待安装结果
while (!obs.finished) {
try
{
obs.wait();
} catch (InterruptedException e) {
}
}
if (obs.result == PackageManager.INSTALL_SUCCEEDED)
{
System.out.println("Success");
} else {
System.err.println("Failure ["+ installFailureToString(obs.result)
+ "]");
}
}
}
catch (RemoteException e) {
System.err.println(e.toString());
System.err.println(PM_NOT_RUNNING_ERR);
}
}
//包安装观察者
class
PackageInstallObserver extends IPackageInstallObserver.Stub
{
boolean finished;
int result;
public void packageInstalled(String name, int status)
{
synchronized( this) {
finished = true;
result = status;
notifyAll();
}
}
}
PackageManagerService与DefaultContainerService
DefaultContainerService源码位于frameworks/base/packages/DefaultContainerService,生成的DefaultContainerService.apk在system/app/目录下,是一个系统级别的应用,不