一、概述
APK為AndroidPackage的縮寫,Android應用安裝有如下四種方式:
(1)系統應用安裝――開機時完成,沒有安裝界面
(2)網絡下載應用安裝――通過market應用完成,沒有安裝界面
(3)ADB工具安裝――沒有安裝界面
(4)第三方應用安裝――通過SD卡里的APK文件安裝,有安裝界面,由 packageinstaller.apk 應用處理安裝及卸載。
應用安裝涉及到如下幾個目錄:
(1)system/app:系統自帶的應用程序,獲得adb root權限才能刪除
(2)data/app:用戶程序安裝的目錄。用戶 安裝時把apk文件 復制 到此目錄
(3)data/data:存放應用程序運行產生的數據
(4)data/dalvik-cache:將apk中的dex文件安裝到dalvik-cache目錄下(dex文件是dalvik虛擬機的可執行文件,其大小約為原始apk文件大小的四分之一)
安裝過程:
(1)復制APK安裝包到data/app目錄下,解壓并掃描安裝包,
(2)將dex文件(Dalvik字節碼)保存到dalvik-cache目錄,
(3)在data/data目錄下創建對應的應用數據目錄。
卸載過程:
刪除 安裝過程中在上述三個目錄下創建的文件及目錄。
1、開機安裝
PackageManagerService處理各種應用的安裝,卸載,管理等工作,開機時由systemServer啟動此服務
(1)首先掃描安裝“system/framework”目錄下的jar包
scanDirLI(mFrameworkDir, PackageParser.PARSE_IS_SYSTEM, scanMode | SCAN_NO_DEX);
(2)掃描安裝“system/app”目錄下的各個系統應用
scanDirLI(mSystemAppDir,PackageParser.PARSE_IS_SYSTEM, scanMode);
掃描“data/app”目錄,即用戶安裝的第三方應用
scanDirLI(mAppInstallDir, 0, scanMode);
掃描" data/app-PRivate"目錄,即安裝DRM保護的APK文件(目前沒有遇到過此類的應用)
scanDirLI(mDrmAppPrivateInstallDir,0, scanMode | SCAN_FORWARD_LOCKED)
(3)安裝應用的過程
scanDirLI(Filedir, int flags, int scanMode) 遍歷安裝指定目錄下的文件
scanPackageLI(FilescanFile,File destCodeFile, FiledestResourceFile, int parseFlags,int scanMode) 安裝package文件
scanPackageLI(File scanFile, File destCodeFile, FiledestResourceFile,PackageParser.Package pkg, intparseFlags, int scanMode)通過解析安裝包parsePackage獲取到安裝包的信息結構
mInstaller.install(pkgName,pkg.applicationInfo.uid,pkg.applicationInfo.uid); 實現文件復制的安裝過程
2、從market上下載應用
Google Market應用需要使用Gmail賬戶登錄才可以使用,選擇某一應用后,開始下載安裝包,此過程中,在手機的信號區有進度條提示,下載完成后,會自動調用PackageManager#installPackage接口
3、從ADB工具安裝
Android Debug Bridge (adb) 是SDK自帶的管理設備的工具,通過ADB命令行的方式也可以為手機或模擬器安裝應用,其入口函數源文件為pm.java
源文件路徑:android/frameworks/base/cmds/pm/src/com/android/commands/pm/pm.java
ADB命令行的形式為adb install <path_to_apk> ,還可以帶安裝參數如:"-l""-r" "-i" "-t"
函數runInstall()中判斷參數:"-l"――INSTALL_FORWARD_LOCK"-r"——INSTALL_REPLACE_EXISTING "-i" ——installerPackageName"-t"——INSTALL_ALLOW_TEST
我們常用的參數為-r,表示覆蓋安裝手機上已安裝的同名應用。從market上下載的應用,也是直接傳入這個參數安裝的。
runInstall與market調用同樣的接口完成應用安裝。
public void installPackage(android.net.Uri packageURI,android.content.pm.ipackageInstallObserver observer, int flags,java.lang.String installerPackageName)
4、第三方應用安裝――通過SD卡里的APK文件安裝
把APK安裝包保存在SD卡中,從手機里訪問SD卡中的APK安裝包,點擊就可以啟動安裝界面,系統應用Packageinstaller.apk處理這種方式下的安裝及卸載界面流程。
首先PackageInstallerActivity負責解析包,判斷是否是可用的Apk文件,然后,創建臨時安裝文件/data/data/com.android.packageinstaller/files/ApiDemos.apk,并啟動安裝確認界面startInstallConfirm,列出解析得到的該應用基本信息。如果手機上已安裝有同名應用,則需要用戶確認是否要替換安裝。確認安裝后,啟動InstallAppProgress,調用安裝接口完成安裝。
pm.installPackage(mPackageURI,observer, installFlags);
【PS】
(1)PackageManagerService.java的內部類AppDirObserver實現了監聽app目錄的功能:當把某個APK拖到app目錄下時,可以直接調用scanPackageLI完成安裝。
(2)手機數據區目錄“data/system/packages.xml”文件中,包含了手機上所有已安裝應用的基本信息,如安裝路徑,申請的permission等信息。
二、PMS#installPackage
installPackage方法中主要調用了installPackageAsUser,其源碼如下:
public void installPackage(String originPath, IPackageInstallObserver2 observer, int installFlags, String installerPackageName, VerificationParams verificationParams, String packageAbiOverride) { installPackageAsUser(originPath, observer, installFlags, installerPackageName, verificationParams, packageAbiOverride, UserHandle.getCallingUserId()); } 再看installPackageAsUser,public void installPackageAsUser(String originPath, IPackageInstallObserver2 observer, int installFlags, String installerPackageName, VerificationParams verificationParams, String packageAbiOverride, int userId) { mContext.enforceCallingOrSelfPermission(android.Manifest.permission.INSTALL_PACKAGES, null); final int callingUid = Binder.getCallingUid(); enforceCrossUserPermission(callingUid, userId, true, true, "installPackageAsUser"); if (isUserRestricted(userId, UserManager.DISALLOW_INSTALL_APPS)) { try { if (observer != null) { observer.onPackageInstalled("", INSTALL_FAILED_USER_RESTRICTED, null, null); } } catch (RemoteException re) { } return; } if ((callingUid == Process.SHELL_UID) || (callingUid == Process.ROOT_UID)) { installFlags |= PackageManager.INSTALL_FROM_ADB; } else { // Caller holds INSTALL_PACKAGES permission, so we're less strict // about installerPackageName. installFlags &= ~PackageManager.INSTALL_FROM_ADB; installFlags &= ~PackageManager.INSTALL_ALL_USERS; } UserHandle user; if ((installFlags & PackageManager.INSTALL_ALL_USERS) != 0) { user = UserHandle.ALL; } else { user = new UserHandle(userId); } // Only system components can circumvent runtime permissions when installing. if ((installFlags & PackageManager.INSTALL_GRANT_RUNTIME_PERMISSIONS) != 0 && mContext.checkCallingOrSelfPermission(Manifest.permission .INSTALL_GRANT_RUNTIME_PERMISSIONS) == PackageManager.PERMISSION_DENIED) { throw new SecurityException("You need the " + "android.permission.INSTALL_GRANT_RUNTIME_PERMISSIONS permission " + "to use the PackageManager.INSTALL_GRANT_RUNTIME_PERMISSIONS flag"); } verificationParams.setInstallerUid(callingUid); final File originFile = new File(originPath); final OriginInfo origin = OriginInfo.fromUntrustedFile(originFile); // 直接交給mHandler來處理了,這個mHandler在PackageManagerService構造函數中初始化,是一個PackageHandler實例 final Message msg = mHandler.obtainMessage(INIT_COPY); msg.obj = new InstallParams(origin, null, observer, installFlags, installerPackageName, null, verificationParams, user, packageAbiOverride, null); mHandler.sendMessage(msg); } 再看PackageHandler類class PackageHandler extends Handler { PackageHandler(Looper looper) { super(looper); } public void handleMessage(Message msg) { try { doHandleMessage(msg); } finally { Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND); } } void doHandleMessage(Message msg) { switch (msg.what) { case INIT_COPY: { HandlerParams params = (HandlerParams) msg.obj; int idx = mPendingInstalls.size(); if (DEBUG_INSTALL) Slog.i(TAG, "init_copy idx=" + idx + ": " + params); // 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_INSTALL) Slog.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) { // Indicate service bind error params.serviceError(); } mPendingInstalls.clear(); } else if (mPendingInstalls.size() > 0) { HandlerParams params = mPendingInstalls.get(0);//獲取第一個任務 if (params != null) { if (params.startCopy()) {//開始安裝 // We are done... look for more work or to // go idle. if (DEBUG_SD_INSTALL) Log.i(TAG, "Checking for more work or unbind..."); // Delete pending install if (mPendingInstalls.size() > 0) { mPendingInstalls.remove(0); } if (mPendingInstalls.size() == 0) { if (mBound) { if (DEBUG_SD_INSTALL) Log.i(TAG, "Posting delayed MCS_UNBIND"); removeMessages(MCS_UNBIND); Message ubmsg = obtainMessage(MCS_UNBIND); // Unbind after a little delay, to avoid // continual thrashing. sendMessageDelayed(ubmsg, 10000); } } else { // There are more pending requests in queue. // Just post MCS_BOUND message to trigger processing // of next pending install. if (DEBUG_SD_INSTALL) Log.i(TAG, "Posting MCS_BOUND for next work"); mHandler.sendEmptyMessage(MCS_BOUND); } } } } else { // Should never happen ideally. Slog.w(TAG, "Empty queue"); } break; } ... } }...} 首先,sendMessage發出的消息由PackageHandler.handleMessage()捕獲,而具體的執行由PackageHandler.doHandleMessage()完成,接著,調用抽象類HandlerParams中的一個startCopy()方法,進而調用scanPackageLI()。
新聞熱點
疑難解答