**應用程序包的安裝是android的特點**
APK為AndroidPackage的縮寫
Android應用安裝有如下四種方式:
1.系統應用安裝――開機時完成,沒有安裝界面
2.網絡下載應用安裝――通過market應用完成,沒有安裝界面
3.ADB工具安裝――沒有安裝界面。
4.第三方應用安裝――通過SD卡里的APK文件安裝,有安裝界面,由???????? packageinstaller.apk應用處理安裝及卸載過程的界面。
應用安裝的流程及路徑?
應用安裝涉及到如下幾個目錄:????????
system/app?---------------系統自帶的應用程序,獲得adb?root權限才能刪除
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包
~~~
//?Find?base?frameworks?(resource?packages?without?code).??
???????????mFrameworkInstallObserver?=?new?AppDirObserver(??
???????????????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的應用程序
~~~
//?Collect?all?system?packages.??
??????????mSystemAppDir?=?new?File(Environment.getRootDirectory(),?"app");??
??????????mSystemInstallObserver?=?new?AppDirObserver(??
??????????????mSystemAppDir.getPath(),?OBSERVER_EVENTS,?true);??
??????????mSystemInstallObserver.startWatching();??
??????????scanDirLI(mSystemAppDir,?PackageParser.PARSE_IS_SYSTEM??
??????????????????|?PackageParser.PARSE_IS_SYSTEM_DIR,?scanMode,?0);??
~~~
3.制造商的目錄下/vendor/app應用包
~~~
//?Collect?all?vendor?packages.??
???????????mVendorAppDir?=?new?File("/vendor/app");??
???????????mVendorInstallObserver?=?new?AppDirObserver(??
???????????????mVendorAppDir.getPath(),?OBSERVER_EVENTS,?true);??
???????????mVendorInstallObserver.startWatching();??
???????????scanDirLI(mVendorAppDir,?PackageParser.PARSE_IS_SYSTEM??
???????????????????|?PackageParser.PARSE_IS_SYSTEM_DIR,?scanMode,?0);??
~~~
4.掃描“data\app”目錄,即用戶安裝的第三方應用
~~~
scanDirLI(mAppInstallDir,?0,?scanMode,?0);??
~~~
5.掃描"?data\app-private"目錄,即安裝DRM保護的APK文件(一個受保護的歌曲或受保 護的視頻是使用?DRM?保護的文件)
~~~
scanDirLI(mDrmAppPrivateInstallDir,?PackageParser.PARSE_FORWARD_LOCK,??
????????????????????scanMode,?0);??
~~~
掃描方法的代碼清單
~~~
private?void?scanDirLI(File?dir,?int?flags,?int?scanMode,?long?currentTime)?{??
????????String[]?files?=?dir.list();??
????????if?(files?==?null)?{??
????????????Log.d(TAG,?"No?files?in?app?dir?"?+?dir);??
????????????return;??
????????}??
????????if?(false)?{??
????????????Log.d(TAG,?"Scanning?app?dir?"?+?dir);??
????????}??
????????int?i;??
????????for?(i=0;?i<files.length;?i++)?{??
????????????File?file?=?new?File(dir,?files[i]);??
????????????if?(!isPackageFilename(files[i]))?{??
????????????????//?Ignore?entries?which?are?not?apk's??
????????????????continue;??
????????????}??
????????????PackageParser.Package?pkg?=?scanPackageLI(file,??
????????????????????flags|PackageParser.PARSE_MUST_BE_APK,?scanMode,?currentTime);??
????????????//?Don't?mess?around?with?apps?in?system?partition.??
????????????if?(pkg?==?null?&&?(flags?&?PackageParser.PARSE_IS_SYSTEM)?==?0?&&??
????????????????????mLastScanError?==?PackageManager.INSTALL_FAILED_INVALID_APK)?{??
????????????????//?Delete?the?apk??
????????????????Slog.w(TAG,?"Cleaning?up?failed?install?of?"?+?file);??
????????????????file.delete();??
????????????}??
????????}??
????}??
~~~
并且從該掃描方法中可以看出調用了scanPackageLI()
private?PackageParser.Package?scanPackageLI(File?scanFile,
int?parseFlags,?int?scanMode,?long?currentTime)
跟蹤scanPackageLI()方法后發現,程序經過很多次的if?else?的篩選,最后判定可以安裝后調用了?mInstaller.install
~~~
if?(mInstaller?!=?null)?{??
????????????????????int?ret?=?mInstaller.install(pkgName,?useEncryptedFSDir,??pkg.applicationInfo.uid,pkg.applicationInfo.uid);??
????????????????????if(ret?<?0)?{??
????????????????????????//?Error?from?installer??
????????????????????????mLastScanError?=????PackageManager.INSTALL_FAILED_INSUFFICIENT_STORAGE;??
????????????????????????return?null;??
????????????????????}??
????????????????}??
mInstaller.install()??通過????
??LocalSocketAddress?address?=?new?LocalSocketAddress(
????????????????"installd",?LocalSocketAddress.Namespace.RESERVED);
~~~
指揮installd在C語言的文件中完成工作
PackageManagerService小節?:1)從apk,?xml中載入pacakge信息,?存儲到內部成員變量中,?用于后面的查找.?關鍵的方法是scanPackageLI().
2)各種查詢操作,?包括query?Intent操作.
3)install?package和delete?package的操作.?還有后面的關鍵方法是installPackageLI().
二、從網絡上下載應用:
下載完成后,會自動調用Packagemanager的安裝方法installPackage()
/*?Called?when?a?downloaded?package?installation?has?been?confirmed?by?the?user?*/
由英文注釋可見PackageManagerService類的installPackage()函數為安裝程序入口。
~~~
public?void?installPackage(??
???????????final?Uri?packageURI,?final?IPackageInstallObserver?observer,?final?int?flags,??
???????????final?String?installerPackageName)?{??
???????mContext.enforceCallingOrSelfPermission(??
???????????????android.Manifest.permission.INSTALL_PACKAGES,?null);??
???????Message?msg?=?mHandler.obtainMessage(INIT_COPY);??
???????msg.obj?=?new?InstallParams(packageURI,?observer,?flags,??
???????????????installerPackageName);??
???????mHandler.sendMessage(msg);??
???}??
~~~
其中是通過PackageHandler的實例mhandler.sendMessage(msg)把信息發給繼承Handler的類HandleMessage()方法
~~~
class?PackageHandler?extends?Handler{??
???????????????????
*****************省略若干********************??
?????????public?void?handleMessage(Message?msg)?{??
????????????try?{??
????????????????doHandleMessage(msg);??
????????????}?finally?{??
????????????????Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);??
????????????}??
????????}??
???******************省略若干**********************??
?}??
~~~
把信息發給doHandleMessage()方法,方法中用switch()語句進行判定傳來Message
~~~
?void?doHandleMessage(Message?msg)?{??
????????????switch?(msg.what)?{??
?????????????
????????????????case?INIT_COPY:?{??
????????????????????if?(DEBUG_SD_INSTALL)?Log.i(TAG,?"init_copy");??
????????????????????HandlerParams?params?=?(HandlerParams)?msg.obj;??
????????????????????int?idx?=?mPendingInstalls.size();??
????????????????????if?(DEBUG_SD_INSTALL)?Log.i(TAG,?"idx="?+?idx);??
????????????????????//?If?a?bind?was?already?initiated?we?dont?really??
????????????????????//?need?to?do?anything.?The?pending?install??
????????????????????//?will?be?processed?later?on.??
????????????????????if?(!mBound)?{??
????????????????????????//?If?this?is?the?only?one?pending?we?might??
????????????????????????//?have?to?bind?to?the?service?again.??
????????????????????????if?(!connectToService())?{??
????????????????????????????Slog.e(TAG,?"Failed?to?bind?to?media?container?service");??
????????????????????????????params.serviceError();??
????????????????????????????return;??
????????????????????????}?else?{??
????????????????????????????//?Once?we?bind?to?the?service,?the?first??
????????????????????????????//?pending?request?will?be?processed.??
????????????????????????????mPendingInstalls.add(idx,?params);??
????????????????????????}??
????????????????????}?else?{??
????????????????????????mPendingInstalls.add(idx,?params);??
????????????????????????//?Already?bound?to?the?service.?Just?make??
????????????????????????//?sure?we?trigger?off?processing?the?first?request.??
????????????????????????if?(idx?==?0)?{??
????????????????????????????mHandler.sendEmptyMessage(MCS_BOUND);??
????????????????????????}??
????????????????????}??
????????????????????break;??
????????????????}??
????????????????case?MCS_BOUND:?{??
????????????????????if?(DEBUG_SD_INSTALL)?Log.i(TAG,?"mcs_bound");??
????????????????????if?(msg.obj?!=?null)?{??
????????????????????????mContainerService?=?(IMediaContainerService)?msg.obj;??
????????????????????}??
????????????????????if?(mContainerService?==?null)?{??
????????????????????????//?Something?seriously?wrong.?Bail?out??
????????????????????????Slog.e(TAG,?"Cannot?bind?to?media?container?service");??
????????????????????????for?(HandlerParams?params?:?mPendingInstalls)?{??
????????????????????????????mPendingInstalls.remove(0);??
????????????????????????????//?Indicate?service?bind?error??
????????????????????????????params.serviceError();??
????????????????????????}??
????????????????????????mPendingInstalls.clear();??
????????????????????}?else?if?(mPendingInstalls.size()?>?0)?{??
????????????????????????HandlerParams?params?=?mPendingInstalls.get(0);??
????????????????????????if?(params?!=?null)?{??
????????????????????????????params.startCopy();??
????????????????????????}??
????????????????????}?else?{??
????????????????????????//?Should?never?happen?ideally.??
????????????????????????Slog.w(TAG,?"Empty?queue");??
????????????????????}??
????????????????????break;??
????????????????}??
????????????****************省略若干**********************??
}??
}???????????????
~~~
public?final?boolean?sendMessage?([Message](http://developer.android.com/reference/android/os/Message.html)?msg)
public?final?boolean?sendEmptyMessage?(int?what)
兩者參數有別。
然后調用抽象類HandlerParams中的一個startCopy()方法
~~~
abstract?class?HandlerParams?{
final?void?startCopy()?{
???***************若干if語句判定否這打回handler消息*******
handleReturnCode();
}
}
~~~
handleReturnCode()復寫了兩次其中有一次是刪除時要調用的,只列出安裝調用的一個方法
~~~
@Override??
???????void?handleReturnCode()?{??
???????????//?If?mArgs?is?null,?then?MCS?couldn't?be?reached.?When?it??
???????????//?reconnects,?it?will?try?again?to?install.?At?that?point,?this??
???????????//?will?succeed.??
???????????if?(mArgs?!=?null)?{??
???????????????processPendingInstall(mArgs,?mRet);??
???????????}??
???????}??
~~~
這時可以清楚的看見?processPendingInstall()被調用。
其中run()方法如下
~~~
run(){??
synchronized?(mInstallLock)?{??
????????????????????????************省略*****************??
????????????????????????installPackageLI(args,?true,?res);??
?????????????????????
?}??
}??
instaPacakgeLI()args,res參數分析??
~~~
-----------------------------------------------------------------------------------------
//InstallArgs?是在PackageService定義的static?abstract?class?InstallArgs?靜態抽象類。
~~~
static?abstract?class?InstallArgs?{??
*********************************************************************??
其中定義了flag標志,packageURL,創建文件,拷貝apk,修改包名稱,??
????????????????????還有一些刪除文件的清理,釋放存儲函數。??
????*********************************************************************??
}??
??class?PackageInstalledInfo?{??
????????String?name;??
????????int?uid;??
????????PackageParser.Package?pkg;??
????????int?returnCode;??
????????PackageRemovedInfo?removedInfo;??
?}??
~~~
-----------------------------------------------------------------------------------------
~~~
private?void?installPackageLI(InstallArgs?args,??
??????????boolean?newInstall,?PackageInstalledInfo?res)?{??
??????int?pFlags?=?args.flags;??
??????String?installerPackageName?=?args.installerPackageName;??
??????File?tmpPackageFile?=?new?File(args.getCodePath());??
??????boolean?forwardLocked?=?((pFlags?&?PackageManager.INSTALL_FORWARD_LOCK)?!=?0);??
??????boolean?onSd?=?((pFlags?&?PackageManager.INSTALL_EXTERNAL)?!=?0);??
??????boolean?replace?=?false;??
??????int?scanMode?=?(onSd???0?:?SCAN_MONITOR)?|?SCAN_FORCE_DEX?|?SCAN_UPDATE_SIGNATURE??
??????????????|?(newInstall???SCAN_NEW_INSTALL?:?0);??
??????//?Result?object?to?be?returned??
??????res.returnCode?=?PackageManager.INSTALL_SUCCEEDED;??
??????//?Retrieve?PackageSettings?and?parse?package??
??????int?parseFlags?=?PackageParser.PARSE_CHATTY?|??
??????(forwardLocked???PackageParser.PARSE_FORWARD_LOCK?:?0)?|??
??????(onSd???PackageParser.PARSE_ON_SDCARD?:?0);??
??????parseFlags?|=?mDefParseFlags;??
??????PackageParser?pp?=?new?PackageParser(tmpPackageFile.getPath());??
??????pp.setSeparateProcesses(mSeparateProcesses);??
??????final?PackageParser.Package?pkg?=?pp.parsePackage(tmpPackageFile,??
??????????????null,?mMetrics,?parseFlags);??
??????if?(pkg?==?null)?{??
??????????res.returnCode?=?pp.getParseError();??
??????????return;??
??????}??
??????String?pkgName?=?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;??
??????}??
??????//?Get?rid?of?all?references?to?package?scan?path?via?parser.??
??????pp?=?null;??
??????String?oldCodePath?=?null;??
??????boolean?systemApp?=?false;??
??????synchronized?(mPackages)?{??
??????????//?Check?if?installing?already?existing?package??
??????????if?((pFlags&PackageManager.INSTALL_REPLACE_EXISTING)?!=?0)?{??
??????????????String?oldName?=?mSettings.mRenamedPackages.get(pkgName);??
??????????????if?(pkg.mOriginalPackages?!=?null??
??????????????????????&&?pkg.mOriginalPackages.contains(oldName)??
??????????????????????&&?mPackages.containsKey(oldName))?{??
??????????????????//?This?package?is?derived?from?an?original?package,??
??????????????????//?and?this?device?has?been?updating?from?that?original??
??????????????????//?name.??We?must?continue?using?the?original?name,?so??
??????????????????//?rename?the?new?package?here.??
??????????????????pkg.setPackageName(oldName);??
??????????????????pkgName?=?pkg.packageName;??
??????????????????replace?=?true;??
??????????????}?else?if?(mPackages.containsKey(pkgName))?{??
??????????????????//?This?package,?under?its?official?name,?already?exists??
??????????????????//?on?the?device;?we?should?replace?it.??
??????????????????replace?=?true;??
??????????????}??
??????????}??
??????????PackageSetting?ps?=?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)?{??
??????????//?Disable?updates?to?system?apps?on?sdcard??
??????????Slog.w(TAG,?"Cannot?install?updates?to?system?apps?on?sdcard");??
??????????res.returnCode?=?PackageManager.INSTALL_FAILED_INVALID_INSTALL_LOCATION;??
??????????return;??
??????}??
??????if?(!args.doRename(res.returnCode,?pkgName,?oldCodePath))?{??
??????????res.returnCode?=?PackageManager.INSTALL_FAILED_INSUFFICIENT_STORAGE;??
??????????return;??
??????}??
??????//?Set?application?objects?path?explicitly?after?the?rename??
??????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()
~~~
private?void?installNewPackageLI(PackageParser.Package?pkg,??
????????????int?parseFlags,int?scanMode,??
????????????String?installerPackageName,?PackageInstalledInfo?res)?{??
?????***********************省略若干*************************************************??
????????PackageParser.Package?newPackage?=?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就是使用方法
~~~
private static void showUsage() {
System.err.println("usage: pm [list|path|install|uninstall]");
System.err.println(" pm list packages [-f]");
System.err.println(" pm list permission-groups");
System.err.println(" pm list permissions [-g] [-f] [-d] [-u] [GROUP]");
System.err.println(" pm list instrumentation [-f] [TARGET-PACKAGE]");
System.err.println(" pm list features");
System.err.println(" pm path PACKAGE");
System.err.println(" pm install [-l] [-r] [-t] [-i INSTALLER_PACKAGE_NAME] [-s] [-f] PATH");
System.err.println(" pm uninstall [-k] PACKAGE");
System.err.println(" pm enable PACKAGE_OR_COMPONENT");
System.err.println(" pm disable PACKAGE_OR_COMPONENT");
System.err.println(" pm setInstallLocation [0/auto] [1/internal] [2/external]");
**********************省略**************************
}
~~~
安裝時候會調用?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();
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);
}
}
~~~
其中的???
???
PackageInstallObserver?obs?=?new?PackageInstallObserver();
????????
????????????mPm.installPackage(Uri.fromFile(new?File(apkFilePath)),?obs,?installFlags,
????????????????????installerPackageName);
如果安裝成功
obs.result?==?PackageManager.INSTALL_SUCCEEDED)
又因為有
IPackageManage?mPm;
????????mPm?=?IpackageManager.Stub.asInterface(ServiceManager.getService("package"));
Stub是接口IPackageManage的靜態抽象類,asInterface是返回IPackageManager代理的靜態方法。
因為class?PackageManagerService?extends?IPackageManager.Stub
所以mPm.installPackage?調用?
????/*?Called?when?a?downloaded?package?installation?has?been?confirmed?by?the?user?*/
????public?void?installPackage(
????????????final?Uri?packageURI,?final?IPackageInstallObserver?observer,?final?int?flags,final?String?installerPackageName)?
這樣就是從網絡下載安裝的入口了。
四,從SD卡安裝
系統調用PackageInstallerActivity.java(/home/zhongda/androidSRC/vortex-8inch-for-hoperun/packages/apps/PackageInstaller/src/com/android/packageinstaller)
進入這個Activity會判斷信息是否有錯,然后調用
??????private?void?initiateInstall()判斷是否曾經有過同名包的安裝,或者包已經安裝
通過后執行private?void?startInstallConfirm()?點擊OK按鈕后經過一系列的安裝信息的判斷Intent跳轉到
~~~
public class InstallAppProgress extends Activity implements View.OnClickListener, OnCancelListener
public void onCreate(Bundle icicle) {
super.onCreate(icicle);
Intent intent = getIntent();
mAppInfo = intent.getParcelableExtra(PackageUtil.INTENT_ATTR_APPLICATION_INFO);
mPackageURI = intent.getData();
initView();
}
~~~
方法中調用了initView()方法
~~~
public void initView() {
requestWindowFeature(Window.FEATURE_NO_TITLE);
setContentView(R.layout.op_progress);
int installFlags = 0;
PackageManager pm = getPackageManager();
try {
PackageInfo pi = pm.getPackageInfo(mAppInfo.packageName,
PackageManager.GET_UNINSTALLED_PACKAGES);
if(pi != null) {
installFlags |= PackageManager.INSTALL_REPLACE_EXISTING;
}
} catch (NameNotFoundException e) {
}
if((installFlags & PackageManager.INSTALL_REPLACE_EXISTING )!= 0) {
Log.w(TAG, "Replacing package:" + mAppInfo.packageName);
}
PackageUtil.AppSnippet as = 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);
// Hide button till progress is being displayed
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);
String installerPackageName = getIntent().getStringExtra(
Intent.EXTRA_INSTALLER_PACKAGE_NAME);
PackageInstallObserver observer = new PackageInstallObserver();
pm.installPackage(mPackageURI, observer, installFlags, installerPackageName);
}
~~~
方法最后我們可以看到再次調用安裝接口完成安裝。
- 前言
- Android觸摸屏事件派發機制詳解與源碼分析一(View篇)
- Android觸摸屏事件派發機制詳解與源碼分析二(ViewGroup篇)
- Android觸摸屏事件派發機制詳解與源碼分析三(Activity篇)
- Android應用setContentView與LayoutInflater加載解析機制源碼分析
- Android應用Context詳解及源碼解析
- Android異步消息處理機制詳解及源碼分析
- Android應用Activity、Dialog、PopWindow、Toast窗口添加機制及源碼分析
- Android ListView工作原理完全解析,帶你從源碼的角度徹底理解
- Activity啟動過程全解析
- Android應用AsyncTask處理機制詳解及源碼分析
- 說說 PendingIntent 的內部機制
- Android Activity.startActivity流程簡介
- Activity界面顯示全解析
- 框架層理解Activity生命周期(APP啟動過程)
- APK安裝過程及原理詳解
- Android構建過程簡述
- Android應用層View繪制流程與源碼分析