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);
 }

相关推荐