PacakgeManagerService学习笔记八-APK installation
来源:互联网 发布:mac只安装win10 编辑:程序博客网 时间:2024/05/17 08:37
<----接上---->
/*DefaultContainerService.java*/
1. getMinimalPackageInfo: 获取一个PackageInfoLite对象
public PackageInfoLite getMinimalPackageInfo(final Uri fileUri, int flags, long threshold) { PackageInfoLite ret = new PackageInfoLite(); if (fileUri == null) { Slog.i(TAG, "Invalid package uri " + fileUri); ret.recommendedInstallLocation = PackageHelper.RECOMMEND_FAILED_INVALID_APK; return ret; } String scheme = fileUri.getScheme(); if (scheme != null && !scheme.equals("file")) { Slog.w(TAG, "Falling back to installing on internal storage only"); ret.recommendedInstallLocation = PackageHelper.RECOMMEND_INSTALL_INTERNAL; return ret; } String archiveFilePath = fileUri.getPath(); DisplayMetrics metrics = new DisplayMetrics(); metrics.setToDefaults();/*解析该APK*/ PackageParser.PackageLite pkg = PackageParser.parsePackageLite(archiveFilePath, 0); if (pkg == null) { Slog.w(TAG, "Failed to parse package"); final File apkFile = new File(archiveFilePath); if (!apkFile.exists()) { ret.recommendedInstallLocation = PackageHelper.RECOMMEND_FAILED_INVALID_URI; } else { ret.recommendedInstallLocation = PackageHelper.RECOMMEND_FAILED_INVALID_APK; } return ret; } ret.packageName = pkg.packageName; ret.installLocation = pkg.installLocation; ret.verifiers = pkg.verifiers;/*取得一个合理的安装位置*/ ret.recommendedInstallLocation = recommendAppInstallLocation(pkg.installLocation, archiveFilePath, flags, threshold); return ret; }2. recommandedAppInstallLocation: 获取一个合理的安装位置
1> 当APK的AndroidManifest.xml中设置的位置为AUTO,在具体对应时倾向内部存储空间
2> 用户在Settings数据库中设置的安装位置
3> 检查外部存储或者内部存储是否有足够的空间
private int recommendAppInstallLocation(int installLocation, String archiveFilePath, int flags, long threshold) { int prefer; boolean checkBoth = false; check_inner : { /* * Explicit install flags should override the manifest settings. */ if ((flags & PackageManager.INSTALL_FORWARD_LOCK) != 0) { /* * Forward-locked applications cannot be installed on SD card, * so only allow checking internal storage. */ prefer = PREFER_INTERNAL; break check_inner; } else if ((flags & PackageManager.INSTALL_INTERNAL) != 0) { prefer = PREFER_INTERNAL; break check_inner; } else if ((flags & PackageManager.INSTALL_EXTERNAL) != 0) { prefer = PREFER_EXTERNAL; break check_inner; } /* No install flags. Check for manifest option. */ if (installLocation == PackageInfo.INSTALL_LOCATION_INTERNAL_ONLY) { prefer = PREFER_INTERNAL; break check_inner; } else if (installLocation == PackageInfo.INSTALL_LOCATION_PREFER_EXTERNAL) { prefer = PREFER_EXTERNAL; checkBoth = true; break check_inner; } else if (installLocation == PackageInfo.INSTALL_LOCATION_AUTO) { // We default to preferring internal storage. prefer = PREFER_INTERNAL; checkBoth = true; break check_inner; } // Pick user preference int installPreference = Settings.System.getInt(getApplicationContext() .getContentResolver(), Settings.Secure.DEFAULT_INSTALL_LOCATION, PackageHelper.APP_INSTALL_AUTO); if (installPreference == PackageHelper.APP_INSTALL_INTERNAL) { prefer = PREFER_INTERNAL; break check_inner; } else if (installPreference == PackageHelper.APP_INSTALL_EXTERNAL) { prefer = PREFER_EXTERNAL; break check_inner; } /* * Fall back to default policy of internal-only if nothing else is * specified. */ prefer = PREFER_INTERNAL; } final boolean emulated = Environment.isExternalStorageEmulated(); final File apkFile = new File(archiveFilePath); boolean fitsOnInternal = false; if (checkBoth || prefer == PREFER_INTERNAL) { try { fitsOnInternal = isUnderInternalThreshold(apkFile, threshold); } catch (FileNotFoundException e) { return PackageHelper.RECOMMEND_FAILED_INVALID_URI; } } boolean fitsOnSd = false; if (!emulated && (checkBoth || prefer == PREFER_EXTERNAL)) { try { fitsOnSd = isUnderExternalThreshold(apkFile); } catch (FileNotFoundException e) { return PackageHelper.RECOMMEND_FAILED_INVALID_URI; } } if (prefer == PREFER_INTERNAL) { if (fitsOnInternal) { return PackageHelper.RECOMMEND_INSTALL_INTERNAL; } } else if (!emulated && prefer == PREFER_EXTERNAL) { if (fitsOnSd) { return PackageHelper.RECOMMEND_INSTALL_EXTERNAL; } } if (checkBoth) { if (fitsOnInternal) { return PackageHelper.RECOMMEND_INSTALL_INTERNAL; } else if (!emulated && fitsOnSd) { return PackageHelper.RECOMMEND_INSTALL_EXTERNAL; } } /* * If they requested to be on the external media by default, return that * the media was unavailable. Otherwise, indicate there was insufficient * storage space available. */ if (!emulated && (checkBoth || prefer == PREFER_EXTERNAL) && !Environment.MEDIA_MOUNTED.equals(Environment.getExternalStorageState())) { return PackageHelper.RECOMMEND_MEDIA_UNAVAILABLE; } else { return PackageHelper.RECOMMEND_FAILED_INSUFFICIENT_STORAGE; } }经过以上步骤,会得到一个合理的安装位置,下面开始复制文件:
3. InstallArgs的copyAPK方法
1> /data/app/创建一个临时文件,临时文件名为vmdl-随机数.tmp, 用这样的文件名是防止触发PKMS扫描启动。PKMS通过inotify机制监控了文件系统。
int copyApk(IMediaContainerService imcs, boolean temp) throws RemoteException { if (temp) { // Generate temp file name createCopyFile(); } // Get a ParcelFileDescriptor to write to the output file File codeFile = new File(codeFileName); if (!created) { try { codeFile.createNewFile(); // Set permissions if (!setPermissions()) { // Failed setting permissions. return PackageManager.INSTALL_FAILED_INSUFFICIENT_STORAGE; } } catch (IOException e) { Slog.w(TAG, "Failed to create file " + codeFile); return PackageManager.INSTALL_FAILED_INSUFFICIENT_STORAGE; } } ParcelFileDescriptor out = null; try { out = ParcelFileDescriptor.open(codeFile, ParcelFileDescriptor.MODE_READ_WRITE); } catch (FileNotFoundException e) { Slog.e(TAG, "Failed to create file descriptor for : " + codeFileName); return PackageManager.INSTALL_FAILED_INSUFFICIENT_STORAGE; } // Copy the resource now int ret = PackageManager.INSTALL_FAILED_INSUFFICIENT_STORAGE; try { mContext.grantUriPermission(DEFAULT_CONTAINER_PACKAGE, packageURI, Intent.FLAG_GRANT_READ_URI_PERMISSION); ret = imcs.copyResource(packageURI, out); } finally { try { if (out != null) out.close(); } catch (IOException e) {} mContext.revokeUriPermission(packageURI, Intent.FLAG_GRANT_READ_URI_PERMISSION); } return ret; }
4. handleReturnCode: handleStartCopy执行完后会调用该方法
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); } }5. processPendingInstall主要完成的工作:
1> 调用InstallArgs的doPreInstall方法;
2> 调用installPackageLI方法进行APK安装,该方法内部将调用doRename方法对临时文件改名,另外,还需要扫描此APK文件,将此APK信息加入到PKMS的成员中
3> 调用InstallArgs的doPostInstall方法
4> APK安装完成,向mHandler发送POST_INSTALL消息,该消息标记一个token,通过它可以从mRunningInstalls数组中取得一个PostInstallData对象
private void processPendingInstall(final InstallArgs args, final int currentStatus) { // Queue up an async operation since the package installation may take a little while. mHandler.post(new Runnable() { public void run() { mHandler.removeCallbacks(this); // Result object to be returned/*创建一个PackageInstalledInfo对象*/ PackageInstalledInfo res = new PackageInstalledInfo(); res.returnCode = currentStatus; res.uid = -1; res.pkg = null; res.removedInfo = new PackageRemovedInfo(); if (res.returnCode == PackageManager.INSTALL_SUCCEEDED) {/*调用FileInstallArgs的doPreInstall*/ args.doPreInstall(res.returnCode); synchronized (mInstallLock) {/*调用installPackageLI进行安装*/ installPackageLI(args, true, res); }/*调用FileInstallArgs的doPostInstall*/ args.doPostInstall(res.returnCode); } // A restore should be performed at this point if (a) the install // succeeded, (b) the operation is not an update, and (c) the new // package has a backupAgent defined. final boolean update = res.removedInfo.removedPackage != null; boolean doRestore = (!update && res.pkg != null && res.pkg.applicationInfo.backupAgentName != null); // Set up the post-install work request bookkeeping. This will be used // and cleaned up by the post-install event handling regardless of whether // there's a restore pass performed. Token values are >= 1. int token; if (mNextInstallToken < 0) mNextInstallToken = 1; token = mNextInstallToken++; PostInstallData data = new PostInstallData(args, res);/*保存对象到mRunningInstalls*/ mRunningInstalls.put(token, data); if (DEBUG_INSTALL) Log.v(TAG, "+ starting restore round-trip " + token); if (res.returnCode == PackageManager.INSTALL_SUCCEEDED && doRestore) { // Pass responsibility to the Backup Manager. It will perform a // restore if appropriate, then pass responsibility back to the // Package Manager to run the post-install observer callbacks // and broadcasts. IBackupManager bm = IBackupManager.Stub.asInterface( ServiceManager.getService(Context.BACKUP_SERVICE)); if (bm != null) { if (DEBUG_INSTALL) Log.v(TAG, "token " + token + " to BM for possible restore"); try { bm.restoreAtInstall(res.pkg.applicationInfo.packageName, token); } catch (RemoteException e) { // can't happen; the backup manager is local } catch (Exception e) { Slog.e(TAG, "Exception trying to enqueue restore", e); doRestore = false; } } else { Slog.e(TAG, "Backup Manager not found!"); doRestore = false; } } if (!doRestore) { // No restore possible, or the Backup Manager was mysteriously not // available -- just fire the post-install work request directly. if (DEBUG_INSTALL) Log.v(TAG, "No restore - queue post-install for " + token);/*发一个消息给mHandler*/ Message msg = mHandler.obtainMessage(POST_INSTALL, token, 0); mHandler.sendMessage(msg); } } }); }
6. POST_INSTALL
/*省略*/case POST_INSTALL: { if (DEBUG_INSTALL) Log.v(TAG, "Handling post-install for " + msg.arg1); PostInstallData data = mRunningInstalls.get(msg.arg1); mRunningInstalls.delete(msg.arg1); boolean deleteOld = false; if (data != null) { InstallArgs args = data.args; PackageInstalledInfo res = data.res; if (res.returnCode == PackageManager.INSTALL_SUCCEEDED) { res.removedInfo.sendBroadcast(false, true); Bundle extras = new Bundle(1); extras.putInt(Intent.EXTRA_UID, res.uid); final boolean update = res.removedInfo.removedPackage != null; if (update) { extras.putBoolean(Intent.EXTRA_REPLACING, true); }/*发送PACKAGE_ADDED广播*/ sendPackageBroadcast(Intent.ACTION_PACKAGE_ADDED, res.pkg.applicationInfo.packageName, extras, null, null); if (update) { sendPackageBroadcast(Intent.ACTION_PACKAGE_REPLACED, res.pkg.applicationInfo.packageName, extras, null, null); sendPackageBroadcast(Intent.ACTION_MY_PACKAGE_REPLACED, null, null, res.pkg.applicationInfo.packageName, null); } if (res.removedInfo.args != null) { // Remove the replaced package's older resources safely now deleteOld = true; } } // Force a gc to clear up things Runtime.getRuntime().gc(); // We delete after a gc for applications on sdcard. if (deleteOld) { synchronized (mInstallLock) { res.removedInfo.args.doPostDeleteLI(true); } } if (args.observer != null) { try {/*通知pm安装结果*/ args.observer.packageInstalled(res.name, res.returnCode); } catch (RemoteException e) { Slog.i(TAG, "Observer no longer exists."); } } } else { Slog.e(TAG, "Bogus post-install token " + msg.arg1); } } break;/*省略*/至此,APK安装完成。
0 0
- PacakgeManagerService学习笔记八-APK installation
- PacakgeManagerService学习笔记七-APK installation
- PacakgeManagerService学习笔记九-APK installation
- Allegro学习笔记八
- 汇编语言学习笔记(八)
- C#学习笔记(八)
- HTML学习笔记八
- Struts2学习笔记八
- Oracle学习笔记(八)
- java学习笔记(八)
- oracle11g学习笔记(八)
- 学习笔记(八)
- c++学习笔记八
- OpenGL学习笔记(八)
- Java学习笔记八
- Django 学习笔记(八)
- MFC学习笔记(八)
- 学习数据库笔记八
- DevExpress GridControl gridView 主从表
- Mac IOS 10.9 java 1.6 与tomcat 8 的问题
- uva 10071 Back to High School Physics
- sqoop的安装使用
- 使用 jsoup 对 HTML 文档进行解析和操作
- PacakgeManagerService学习笔记八-APK installation
- ThinkPad E531 68851C1 预装Win8系统环境下安装Win7双系统
- 地雷和蜘蛛你选什么?
- online judge(ACM) 的设计与分析 (有c#demo)
- IOS 一些简单的数字随机算法 去重等功能
- 简介跨平台的移动开发框架!
- ifcfg-eth0 设置与解释
- 年夜饭
- arm交叉编译Valgrind