android 应用的安装过程
转载自
[url]
http://blog.csdn.net/hdhd588/article/details/6739281#comments
[/url]
APK安装过程及原理详解
2011-09-0114:0913614人阅读评论(7)收藏举报
nullsysteminstallerframeworksstringfile
应用程序包的安装是android的特点
APK为AndroidPackage的缩写
Android应用安装有如下四种方式:
1.系统应用安装――开机时完成,没有安装界面
2.网络下载应用安装――通过market应用完成,没有安装界面
3.ADB工具安装――没有安装界面。
4.第三方应用安装――通过SD卡里的APK文件安装,有安装界面,由packageinstaller.apk应用处理安装及卸载过程的界面。
应用安装的流程及路径
应用安装涉及到如下几个目录:
system/app---------------系统自带的应用程序,获得adbroot权限才能删除
data/app---------------用户程序安装的目录。安装时把apk文件复制到此目录
data/data---------------存放应用程序的数据
data/dalvik-cache--------将apk中的dex文件安装到dalvik-cache目录下(dex文件是dalvik虚拟机的可执行文件,其大小约为原始apk文件大小的四分之一)
安装过程:
复制APK安装包到data/app目录下,解压并扫描安装包,把dex文件(Dalvik字节码)保存到dalvik-cache目录,并data/data目录下创建对应的应用数据目录。
卸载过程:
删除安装过程中在上述三个目录下创建的文件及目录。
安装应用的过程解析
一.开机安装
PackageManagerService处理各种应用的安装,卸载,管理等工作,开机时由systemServer启动此服务
(源文件路径:android\frameworks\base\services\java\com\android\server\PackageManagerService.java)
PackageManagerService服务启动的流程:
1.首先扫描安装“system\framework”目录下的jar包
[java]viewplaincopy
//Findbaseframeworks(resourcepackageswithoutcode).
mFrameworkInstallObserver=newAppDirObserver(
mFrameworkDir.getPath(),OBSERVER_EVENTS,true);
mFrameworkInstallObserver.startWatching();
scanDirLI(mFrameworkDir,PackageParser.PARSE_IS_SYSTEM
|PackageParser.PARSE_IS_SYSTEM_DIR,
scanMode|SCAN_NO_DEX,0);
2.扫描安装系统system/app的应用程序
[java]viewplaincopy
//Collectallsystempackages.
mSystemAppDir=newFile(Environment.getRootDirectory(),"app");
mSystemInstallObserver=newAppDirObserver(
mSystemAppDir.getPath(),OBSERVER_EVENTS,true);
mSystemInstallObserver.startWatching();
scanDirLI(mSystemAppDir,PackageParser.PARSE_IS_SYSTEM
|PackageParser.PARSE_IS_SYSTEM_DIR,scanMode,0);
3.制造商的目录下/vendor/app应用包
[java]viewplaincopy
//Collectallvendorpackages.
mVendorAppDir=newFile("/vendor/app");
mVendorInstallObserver=newAppDirObserver(
mVendorAppDir.getPath(),OBSERVER_EVENTS,true);
mVendorInstallObserver.startWatching();
scanDirLI(mVendorAppDir,PackageParser.PARSE_IS_SYSTEM
|PackageParser.PARSE_IS_SYSTEM_DIR,scanMode,0);
4.扫描“data\app”目录,即用户安装的第三方应用
[java]viewplaincopy
scanDirLI(mAppInstallDir,0,scanMode,0);
5.扫描"data\app-private"目录,即安装DRM保护的APK文件(一个受保护的歌曲或受保护的视频是使用DRM保护的文件)
[java]viewplaincopy
scanDirLI(mDrmAppPrivateInstallDir,PackageParser.PARSE_FORWARD_LOCK,
scanMode,0);
扫描方法的代码清单
[java]viewplaincopy
privatevoidscanDirLI(Filedir,intflags,intscanMode,longcurrentTime){
String[]files=dir.list();
if(files==null){
Log.d(TAG,"Nofilesinappdir"+dir);
return;
}
if(false){
Log.d(TAG,"Scanningappdir"+dir);
}
inti;
for(i=0;i<files.length;i++){
Filefile=newFile(dir,files[i]);
if(!isPackageFilename(files[i])){
//Ignoreentrieswhicharenotapk's
continue;
}
PackageParser.Packagepkg=scanPackageLI(file,
flags|PackageParser.PARSE_MUST_BE_APK,scanMode,currentTime);
//Don'tmessaroundwithappsinsystempartition.
if(pkg==null&&(flags&PackageParser.PARSE_IS_SYSTEM)==0&&
mLastScanError==PackageManager.INSTALL_FAILED_INVALID_APK){
//Deletetheapk
Slog.w(TAG,"Cleaningupfailedinstallof"+file);
file.delete();
}
}
}
并且从该扫描方法中可以看出调用了scanPackageLI()
privatePackageParser.PackagescanPackageLI(FilescanFile,
intparseFlags,intscanMode,longcurrentTime)
跟踪scanPackageLI()方法后发现,程序经过很多次的ifelse的筛选,最后判定可以安装后调用了mInstaller.install
[java]viewplaincopy
if(mInstaller!=null){
intret=mInstaller.install(pkgName,useEncryptedFSDir,pkg.applicationInfo.uid,pkg.applicationInfo.uid);
if(ret<0){
//Errorfrominstaller
mLastScanError=PackageManager.INSTALL_FAILED_INSUFFICIENT_STORAGE;
returnnull;
}
}
mInstaller.install()通过
LocalSocketAddressaddress=newLocalSocketAddress(
"installd",LocalSocketAddress.Namespace.RESERVED);
指挥installd在C语言的文件中完成工作
PackageManagerService小节:1)从apk,xml中载入pacakge信息,存储到内部成员变量中,用于后面的查找.关键的方法是scanPackageLI().
2)各种查询操作,包括queryIntent操作.
3)installpackage和deletepackage的操作.还有后面的关键方法是installPackageLI().
二、从网络上下载应用:
下载完成后,会自动调用Packagemanager的安装方法installPackage()
/*Calledwhenadownloadedpackageinstallationhasbeenconfirmedbytheuser*/
由英文注释可见PackageManagerService类的installPackage()函数为安装程序入口。
[java]viewplaincopy
publicvoidinstallPackage(
finalUripackageURI,finalIPackageInstallObserverobserver,finalintflags,
finalStringinstallerPackageName){
mContext.enforceCallingOrSelfPermission(
android.Manifest.permission.INSTALL_PACKAGES,null);
Messagemsg=mHandler.obtainMessage(INIT_COPY);
msg.obj=newInstallParams(packageURI,observer,flags,
installerPackageName);
mHandler.sendMessage(msg);
}
其中是通过PackageHandler的实例mhandler.sendMessage(msg)把信息发给继承Handler的类HandleMessage()方法
[java]viewplaincopy
classPackageHandlerextendsHandler{
*****************省略若干********************
publicvoidhandleMessage(Messagemsg){
try{
doHandleMessage(msg);
}finally{
Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
}
}
******************省略若干**********************
}
把信息发给doHandleMessage()方法,方法中用switch()语句进行判定传来Message
[java]viewplaincopy
voiddoHandleMessage(Messagemsg){
switch(msg.what){
caseINIT_COPY:{
if(DEBUG_SD_INSTALL)Log.i(TAG,"init_copy");
HandlerParamsparams=(HandlerParams)msg.obj;
intidx=mPendingInstalls.size();
if(DEBUG_SD_INSTALL)Log.i(TAG,"idx="+idx);
//Ifabindwasalreadyinitiatedwedontreally
//needtodoanything.Thependinginstall
//willbeprocessedlateron.
if(!mBound){
//Ifthisistheonlyonependingwemight
//havetobindtotheserviceagain.
if(!connectToService()){
Slog.e(TAG,"Failedtobindtomediacontainerservice");
params.serviceError();
return;
}else{
//Oncewebindtotheservice,thefirst
//pendingrequestwillbeprocessed.
mPendingInstalls.add(idx,params);
}
}else{
mPendingInstalls.add(idx,params);
//Alreadyboundtotheservice.Justmake
//surewetriggeroffprocessingthefirstrequest.
if(idx==0){
mHandler.sendEmptyMessage(MCS_BOUND);
}
}
break;
}
caseMCS_BOUND:{
if(DEBUG_SD_INSTALL)Log.i(TAG,"mcs_bound");
if(msg.obj!=null){
mContainerService=(IMediaContainerService)msg.obj;
}
if(mContainerService==null){
//Somethingseriouslywrong.Bailout
Slog.e(TAG,"Cannotbindtomediacontainerservice");
for(HandlerParamsparams:mPendingInstalls){
mPendingInstalls.remove(0);
//Indicateservicebinderror
params.serviceError();
}
mPendingInstalls.clear();
}elseif(mPendingInstalls.size()>0){
HandlerParamsparams=mPendingInstalls.get(0);
if(params!=null){
params.startCopy();
}
}else{
//Shouldneverhappenideally.
Slog.w(TAG,"Emptyqueue");
}
break;
}
****************省略若干**********************
}
}
publicfinalbooleansendMessage(Messagemsg)
publicfinalbooleansendEmptyMessage(intwhat)
两者参数有别。
然后调用抽象类HandlerParams中的一个startCopy()方法
abstractclassHandlerParams{
finalvoidstartCopy(){
***************若干if语句判定否这打回handler消息*******
handleReturnCode();
}
}
handleReturnCode()复写了两次其中有一次是删除时要调用的,只列出安装调用的一个方法
[java]viewplaincopy
@Override
voidhandleReturnCode(){
//IfmArgsisnull,thenMCScouldn'tbereached.Whenit
//reconnects,itwilltryagaintoinstall.Atthatpoint,this
//willsucceed.
if(mArgs!=null){
processPendingInstall(mArgs,mRet);
}
}
这时可以清楚的看见processPendingInstall()被调用。
其中run()方法如下
[java]viewplaincopy
run(){
synchronized(mInstallLock){
************省略*****************
installPackageLI(args,true,res);
}
}
instaPacakgeLI()args,res参数分析
-----------------------------------------------------------------------------------------
//InstallArgs是在PackageService定义的staticabstractclassInstallArgs静态抽象类。
[java]viewplaincopy
staticabstractclassInstallArgs{
*********************************************************************
其中定义了flag标志,packageURL,创建文件,拷贝apk,修改包名称,
还有一些删除文件的清理,释放存储函数。
*********************************************************************
}
classPackageInstalledInfo{
Stringname;
intuid;
PackageParser.Packagepkg;
intreturnCode;
PackageRemovedInforemovedInfo;
}
-----------------------------------------------------------------------------------------
[java]viewplaincopy
privatevoidinstallPackageLI(InstallArgsargs,
booleannewInstall,PackageInstalledInfores){
intpFlags=args.flags;
StringinstallerPackageName=args.installerPackageName;
FiletmpPackageFile=newFile(args.getCodePath());
booleanforwardLocked=((pFlags&PackageManager.INSTALL_FORWARD_LOCK)!=0);
booleanonSd=((pFlags&PackageManager.INSTALL_EXTERNAL)!=0);
booleanreplace=false;
intscanMode=(onSd?0:SCAN_MONITOR)|SCAN_FORCE_DEX|SCAN_UPDATE_SIGNATURE
|(newInstall?SCAN_NEW_INSTALL:0);
//Resultobjecttobereturned
res.returnCode=PackageManager.INSTALL_SUCCEEDED;
//RetrievePackageSettingsandparsepackage
intparseFlags=PackageParser.PARSE_CHATTY|
(forwardLocked?PackageParser.PARSE_FORWARD_LOCK:0)|
(onSd?PackageParser.PARSE_ON_SDCARD:0);
parseFlags|=mDefParseFlags;
PackageParserpp=newPackageParser(tmpPackageFile.getPath());
pp.setSeparateProcesses(mSeparateProcesses);
finalPackageParser.Packagepkg=pp.parsePackage(tmpPackageFile,
null,mMetrics,parseFlags);
if(pkg==null){
res.returnCode=pp.getParseError();
return;
}
StringpkgName=res.name=pkg.packageName;
if((pkg.applicationInfo.flags&ApplicationInfo.FLAG_TEST_ONLY)!=0){
if((pFlags&PackageManager.INSTALL_ALLOW_TEST)==0){
res.returnCode=PackageManager.INSTALL_FAILED_TEST_ONLY;
return;
}
}
if(GET_CERTIFICATES&&!pp.collectCertificates(pkg,parseFlags)){
res.returnCode=pp.getParseError();
return;
}
//Getridofallreferencestopackagescanpathviaparser.
pp=null;
StringoldCodePath=null;
booleansystemApp=false;
synchronized(mPackages){
//Checkifinstallingalreadyexistingpackage
if((pFlags&PackageManager.INSTALL_REPLACE_EXISTING)!=0){
StringoldName=mSettings.mRenamedPackages.get(pkgName);
if(pkg.mOriginalPackages!=null
&&pkg.mOriginalPackages.contains(oldName)
&&mPackages.containsKey(oldName)){
//Thispackageisderivedfromanoriginalpackage,
//andthisdevicehasbeenupdatingfromthatoriginal
//name.Wemustcontinueusingtheoriginalname,so
//renamethenewpackagehere.
pkg.setPackageName(oldName);
pkgName=pkg.packageName;
replace=true;
}elseif(mPackages.containsKey(pkgName)){
//Thispackage,underitsofficialname,alreadyexists
//onthedevice;weshouldreplaceit.
replace=true;
}
}
PackageSettingps=mSettings.mPackages.get(pkgName);
if(ps!=null){
oldCodePath=mSettings.mPackages.get(pkgName).codePathString;
if(ps.pkg!=null&&ps.pkg.applicationInfo!=null){
systemApp=(ps.pkg.applicationInfo.flags&
ApplicationInfo.FLAG_SYSTEM)!=0;
}
}
}
if(systemApp&&onSd){
//Disableupdatestosystemappsonsdcard
Slog.w(TAG,"Cannotinstallupdatestosystemappsonsdcard");
res.returnCode=PackageManager.INSTALL_FAILED_INVALID_INSTALL_LOCATION;
return;
}
if(!args.doRename(res.returnCode,pkgName,oldCodePath)){
res.returnCode=PackageManager.INSTALL_FAILED_INSUFFICIENT_STORAGE;
return;
}
//Setapplicationobjectspathexplicitlyaftertherename
setApplicationInfoPaths(pkg,args.getCodePath(),args.getResourcePath());
pkg.applicationInfo.nativeLibraryDir=args.getNativeLibraryPath();
if(replace){
replacePackageLI(pkg,parseFlags,scanMode,
installerPackageName,res);
}else{
installNewPackageLI(pkg,parseFlags,scanMode,
installerPackageName,res);
}
}
最后判断如果以前不存在那么调用installNewPackageLI()
[java]viewplaincopy
privatevoidinstallNewPackageLI(PackageParser.Packagepkg,
intparseFlags,intscanMode,
StringinstallerPackageName,PackageInstalledInfores){
***********************省略若干*************************************************
PackageParser.PackagenewPackage=scanPackageLI(pkg,parseFlags,scanMode,
System.currentTimeMillis());
***********************省略若干**************************************************
}
最后终于回到了和开机安装一样的地方.与开机方式安装调用统一方法。
三、从ADB工具安装
其入口函数源文件为pm.java
(源文件路径:android\frameworks\base\cmds\pm\src\com\android\commands\pm\pm.java)
其中\system\framework\pm.jar包管理库
包管理脚本\system\bin\pm解析
showUsage就是使用方法
[java]viewplaincopy
privatestaticvoidshowUsage(){
System.err.println("usage:pm[list|path|install|uninstall]");
System.err.println("pmlistpackages[-f]");
System.err.println("pmlistpermission-groups");
System.err.println("pmlistpermissions[-g][-f][-d][-u][GROUP]");
System.err.println("pmlistinstrumentation[-f][TARGET-PACKAGE]");
System.err.println("pmlistfeatures");
System.err.println("pmpathPACKAGE");
System.err.println("pminstall[-l][-r][-t][-iINSTALLER_PACKAGE_NAME][-s][-f]PATH");
System.err.println("pmuninstall[-k]PACKAGE");
System.err.println("pmenablePACKAGE_OR_COMPONENT");
System.err.println("pmdisablePACKAGE_OR_COMPONENT");
System.err.println("pmsetInstallLocation[0/auto][1/internal][2/external]");
**********************省略**************************
}
安装时候会调用runInstall()方法
[java]viewplaincopy
privatevoidrunInstall(){
intinstallFlags=0;
StringinstallerPackageName=null;
Stringopt;
while((opt=nextOption())!=null){
if(opt.equals("-l")){
installFlags|=PackageManager.INSTALL_FORWARD_LOCK;
}elseif(opt.equals("-r")){
installFlags|=PackageManager.INSTALL_REPLACE_EXISTING;
}elseif(opt.equals("-i")){
installerPackageName=nextOptionData();
if(installerPackageName==null){
System.err.println("Error:novaluespecifiedfor-i");
showUsage();
return;
}
}elseif(opt.equals("-t")){
installFlags|=PackageManager.INSTALL_ALLOW_TEST;
}elseif(opt.equals("-s")){
//Overrideif-soptionisspecified.
installFlags|=PackageManager.INSTALL_EXTERNAL;
}elseif(opt.equals("-f")){
//Overrideif-soptionisspecified.
installFlags|=PackageManager.INSTALL_INTERNAL;
}else{
System.err.println("Error:Unknownoption:"+opt);
showUsage();
return;
}
}
StringapkFilePath=nextArg();
System.err.println("\tpkg:"+apkFilePath);
if(apkFilePath==null){
System.err.println("Error:nopackagespecified");
showUsage();
return;
}
PackageInstallObserverobs=newPackageInstallObserver();
try{
mPm.installPackage(Uri.fromFile(newFile(apkFilePath)),obs,installFlags,
installerPackageName);
synchronized(obs){
while(!obs.finished){
try{
obs.wait();
}catch(InterruptedExceptione){
}
}
if(obs.result==PackageManager.INSTALL_SUCCEEDED){
System.out.println("Success");
}else{
System.err.println("Failure["
+installFailureToString(obs.result)
+"]");
}
}
}catch(RemoteExceptione){
System.err.println(e.toString());
System.err.println(PM_NOT_RUNNING_ERR);
}
}
其中的
PackageInstallObserverobs=newPackageInstallObserver();
mPm.installPackage(Uri.fromFile(newFile(apkFilePath)),obs,installFlags,
installerPackageName);
如果安装成功
obs.result==PackageManager.INSTALL_SUCCEEDED)
又因为有
IPackageManagemPm;
mPm=IpackageManager.Stub.asInterface(ServiceManager.getService("package"));
Stub是接口IPackageManage的静态抽象类,asInterface是返回IPackageManager代理的静态方法。
因为classPackageManagerServiceextendsIPackageManager.Stub
所以mPm.installPackage调用
/*Calledwhenadownloadedpackageinstallationhasbeenconfirmedbytheuser*/
publicvoidinstallPackage(
finalUripackageURI,finalIPackageInstallObserverobserver,finalintflags,finalStringinstallerPackageName)
这样就是从网络下载安装的入口了。
四,从SD卡安装
系统调用PackageInstallerActivity.java(/home/zhongda/androidSRC/vortex-8inch-for-hoperun/packages/apps/PackageInstaller/src/com/android/packageinstaller)
进入这个Activity会判断信息是否有错,然后调用
privatevoidinitiateInstall()判断是否曾经有过同名包的安装,或者包已经安装
通过后执行privatevoidstartInstallConfirm()点击OK按钮后经过一系列的安装信息的判断Intent跳转到
[java]viewplaincopy
publicclassInstallAppProgressextendsActivityimplementsView.OnClickListener,OnCancelListener
publicvoidonCreate(Bundleicicle){
super.onCreate(icicle);
Intentintent=getIntent();
mAppInfo=intent.getParcelableExtra(PackageUtil.INTENT_ATTR_APPLICATION_INFO);
mPackageURI=intent.getData();
initView();
}
方法中调用了initView()方法
[java]viewplaincopy
publicvoidinitView(){
requestWindowFeature(Window.FEATURE_NO_TITLE);
setContentView(R.layout.op_progress);
intinstallFlags=0;
PackageManagerpm=getPackageManager();
try{
PackageInfopi=pm.getPackageInfo(mAppInfo.packageName,
PackageManager.GET_UNINSTALLED_PACKAGES);
if(pi!=null){
installFlags|=PackageManager.INSTALL_REPLACE_EXISTING;
}
}catch(NameNotFoundExceptione){
}
if((installFlags&PackageManager.INSTALL_REPLACE_EXISTING)!=0){
Log.w(TAG,"Replacingpackage:"+mAppInfo.packageName);
}
PackageUtil.AppSnippetas=PackageUtil.getAppSnippet(this,mAppInfo,
mPackageURI);
mLabel=as.label;
PackageUtil.initSnippetForNewApp(this,as,R.id.app_snippet);
mStatusTextView=(TextView)findViewById(R.id.center_text);
mStatusTextView.setText(R.string.installing);
mProgressBar=(ProgressBar)findViewById(R.id.progress_bar);
mProgressBar.setIndeterminate(true);
//Hidebuttontillprogressisbeingdisplayed
mOkPanel=(View)findViewById(R.id.buttons_panel);
mDoneButton=(Button)findViewById(R.id.done_button);
mLaunchButton=(Button)findViewById(R.id.launch_button);
mOkPanel.setVisibility(View.INVISIBLE);
StringinstallerPackageName=getIntent().getStringExtra(
Intent.EXTRA_INSTALLER_PACKAGE_NAME);
PackageInstallObserverobserver=newPackageInstallObserver();
pm.installPackage(mPackageURI,observer,installFlags,installerPackageName);
}
方法最后我们可以看到再次调用安装接口完成安装。
安装指定目录的apk
/*** * 安装应用<br> * @param file apk的路径<br> */ private void installApp(String file){ Intent intent = new Intent(Intent.ACTION_VIEW); intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); intent.setDataAndType( Uri.fromFile(new File(file)), "application/vnd.android.package-archive"); startActivity(intent); }
相关推荐
adb shell cd system/app rm *.apk21. 获取管理员权限: adb root22. 启动Activity: adb shell am start -n 包名/包名+类名。