PMS开机安装更新APK流程

PMS开机启动过程就已经将APK扫描安装到系统,但这个流程策略是怎样的呢?

一、扫描所有系统路径下的APK

主要就是调用scanDirLI方法,这个方法又调用scanPackageLI

      scanDirLI(vendorAppDir, PackageParser.PARSE_IS_SYSTEM
                    | PackageParser.PARSE_IS_SYSTEM_DIR, scanFlags, 0);

            /** M: [ALPS00104673][Need Patch][Volunteer Patch]Mechanism for uninstall app from system partition @{ */
            /// M: [ALPS01210636] Unify path from /vendor to /system/vendor/
            /// So that DVM can find the correct odex
            mOperatorAppInstallDir = new File(Environment.getRootDirectory(), "/vendor/operator/app");

            /// M: [ALPS00270065][Urgent] User mode, cannot move applications to SD
            /// M: [ALPS00338366] Add PARSE_IS_OPERATOR for operator apps
            scanDirLI(mOperatorAppInstallDir, PackageParser.PARSE_IS_OPERATOR, scanFlags, 0);
            /** @} */

            /** M: [CIP] Scan CIP app folder @{ */
            mCustomAppInstallDir = new File("/custom/app");

            /// M: App under CIP folder can be uninstalled
            scanDirLI(mCustomAppInstallDir, PackageParser.PARSE_IS_OPERATOR
                    | PackageParser.PARSE_IS_SYSTEM
                    | PackageParser.PARSE_IS_SYSTEM_DIR, scanFlags, 0);
            /** @} */

            /** M: for plugin app @{ */
            /// APP plugin
            mPluginAppInstallDir = new File(Environment.getRootDirectory(), "plugin");

            scanDirLI(mPluginAppInstallDir, PackageParser.PARSE_IS_OPERATOR
                    | PackageParser.PARSE_IS_SYSTEM
                    | PackageParser.PARSE_IS_SYSTEM_DIR, scanFlags, 0);
            /// CIP plugin
            mCustomPluginInstallDir = new File("/custom/plugin");

            /// M: App under CIP folder can be uninstalled
            scanDirLI(mCustomPluginInstallDir, PackageParser.PARSE_IS_OPERATOR
                    | PackageParser.PARSE_IS_SYSTEM
                    | PackageParser.PARSE_IS_SYSTEM_DIR, scanFlags, 0);
            /** @} */

            // Collect all OEM packages.
            final File oemAppDir = new File(Environment.getOemDirectory(), "app");
            scanDirLI(oemAppDir, PackageParser.PARSE_IS_SYSTEM
                    | PackageParser.PARSE_IS_SYSTEM_DIR, scanFlags, 0);

            if (DEBUG_UPGRADE) Log.v(TAG, "Running installd update commands");
            mInstaller.moveFiles();

二、找出那些已经被删除和用户在data分区安装过的APK特殊处理

如果这个扫描出的系统APK是disable状态并且在setting列表,说明这个APK进行过自升级,以用户安装的优先

如果这个APK本次没有在系统路径下扫描到,但setting列表里又存在,说明很可能该APK已经被删除了,所以需要清除APK数据

   // Prune any system packages that no longer exist.
            final List<String> possiblyDeletedUpdatedSystemApps = new ArrayList<String>();
            if (!mOnlyCore) {
                Iterator<PackageSetting> psit = mSettings.mPackages.values().iterator();
                while (psit.hasNext()) {
                    PackageSetting ps = psit.next();

                     /*
                      * If this is not a system app, it can't be a
                      * disable system app.
                      */
                    if ((ps.pkgFlags & ApplicationInfo.FLAG_SYSTEM) == 0) {
                        /// M: [Operator] Operator apps are belong to system domain, therefore, need prune.
                        /// M: [Operator] We should also consider OTA from old version without mtkFlag
                        if (!isVendorApp(ps) && !locationIsOperator(ps.codePath)) {
                            continue;
                        }
                    }

                    /*
                     * If the package is scanned, it's not erased.
                     */
                    final PackageParser.Package scannedPkg = mPackages.get(ps.name);
                    if (scannedPkg != null) {
                        /*
                         * If the system app is both scanned and in the
                         * disabled packages list, then it must have been
                         * added via OTA. Remove it from the currently
                         * scanned package so the previously user-installed
                         * application can be scanned.
                         */
                        if (mSettings.isDisabledSystemPackageLPr(ps.name)) {
                            logCriticalInfo(Log.WARN, "Expecting better updated system app for "
                                    + ps.name + "; removing system app.  Last known codePath="
                                    + ps.codePathString + ", installStatus=" + ps.installStatus
                                    + ", versionCode=" + ps.versionCode + "; scanned versionCode="
                                    + scannedPkg.mVersionCode);
                            removePackageLI(ps, true);
                            mExpectingBetter.put(ps.name, ps.codePath);
                        }

                        continue;
                    }

                    if (!mSettings.isDisabledSystemPackageLPr(ps.name)) {
                        psit.remove();
                        logCriticalInfo(Log.WARN, "System package " + ps.name
                                + " no longer exists; wiping its data");
                        removeDataDirsLI(null, ps.name);
                    } else {
                        final PackageSetting disabledPs = mSettings.getDisabledSystemPkgLPr(ps.name);
                        if (disabledPs.codePath == null || !disabledPs.codePath.exists()) {
                            possiblyDeletedUpdatedSystemApps.add(ps.name);
                        }
                    }
                }
            }

三、处理可能已删除或优先使用data分区的APK

       ArrayList<PackageSetting> deletePkgsList = mSettings.getListOfIncompleteInstallPackagesLPr();
            //clean up list
            for(int i = 0; i < deletePkgsList.size(); i++) {
                //clean up here
                cleanupInstallFailedPackage(deletePkgsList.get(i));
            }
            //delete tmp files
            deleteTempPackageFiles();

            // Remove any shared userIDs that have no associated packages
            mSettings.pruneSharedUsersLPw();

            if (!mOnlyCore) {
                EventLog.writeEvent(EventLogTags.BOOT_PROGRESS_PMS_DATA_SCAN_START,
                        SystemClock.uptimeMillis());
                scanDirLI(mAppInstallDir, 0, scanFlags | SCAN_REQUIRE_KNOWN, 0);

                scanDirLI(mDrmAppPrivateInstallDir, PackageParser.PARSE_FORWARD_LOCK,
                        scanFlags | SCAN_REQUIRE_KNOWN, 0);

                /**
                 * Remove disable package settings for any updated system
                 * apps that were removed via an OTA. If they're not a
                 * previously-updated app, remove them completely.
                 * Otherwise, just revoke their system-level permissions.
                 */
                for (String deletedAppName : possiblyDeletedUpdatedSystemApps) {
                    PackageParser.Package deletedPkg = mPackages.get(deletedAppName);
                    mSettings.removeDisabledSystemPackageLPw(deletedAppName);

                    String msg;
                    if (deletedPkg == null) {
                        msg = "Updated system package " + deletedAppName
                                + " no longer exists; wiping its data";
                        removeDataDirsLI(null, deletedAppName);
                    } else {
                        msg = "Updated system app + " + deletedAppName
                                + " no longer present; removing system privileges for "
                                + deletedAppName;

                        deletedPkg.applicationInfo.flags &= ~ApplicationInfo.FLAG_SYSTEM;

                        /// M: [Operator] Revoke operator permissions for the original operator package
                        /// under operator folder was gone due to OTA
                        deletedPkg.applicationInfo.flagsEx &= ~ApplicationInfo.FLAG_EX_OPERATOR;

                        PackageSetting deletedPs = mSettings.mPackages.get(deletedAppName);
                        deletedPs.pkgFlags &= ~ApplicationInfo.FLAG_SYSTEM;

                        /// M: [Operator] Revoke vendor permissions
                        deletedPs.pkgFlagsEx &= ~ApplicationInfo.FLAG_EX_OPERATOR;
                    }
                    logCriticalInfo(Log.WARN, msg);
                }

                /**
                 * Make sure all system apps that we expected to appear on
                 * the userdata partition actually showed up. If they never
                 * appeared, crawl back and revive the system version.
                 */
                for (int i = 0; i < mExpectingBetter.size(); i++) {
                    final String packageName = mExpectingBetter.keyAt(i);
                    if (!mPackages.containsKey(packageName)) {
                        final File scanFile = mExpectingBetter.valueAt(i);

                        logCriticalInfo(Log.WARN, "Expected better " + packageName
                                + " but never showed up; reverting to system");

                        final int reparseFlags;
                        if (FileUtils.contains(privilegedAppDir, scanFile)) {
                            reparseFlags = PackageParser.PARSE_IS_SYSTEM
                                    | PackageParser.PARSE_IS_SYSTEM_DIR
                                    | PackageParser.PARSE_IS_PRIVILEGED;
                        } else if (FileUtils.contains(systemAppDir, scanFile)) {
                            reparseFlags = PackageParser.PARSE_IS_SYSTEM
                                    | PackageParser.PARSE_IS_SYSTEM_DIR;
                        } else if (FileUtils.contains(vendorAppDir, scanFile)) {
                            reparseFlags = PackageParser.PARSE_IS_SYSTEM
                                    | PackageParser.PARSE_IS_SYSTEM_DIR;
                        } else if (FileUtils.contains(oemAppDir, scanFile)) {
                            reparseFlags = PackageParser.PARSE_IS_SYSTEM
                                    | PackageParser.PARSE_IS_SYSTEM_DIR;
                        } else {
                            Slog.e(TAG, "Ignoring unexpected fallback path " + scanFile);
                            continue;
                        }

                        mSettings.enableSystemPackageLPw(packageName);

                        try {
                            scanPackageLI(scanFile, reparseFlags, scanFlags, 0, null);
                        } catch (PackageManagerException e) {
                            Slog.e(TAG, "Failed to parse original system package: "
                                    + e.getMessage());
                        }
                    }
                }
            }
            mExpectingBetter.clear();

系统APK的覆盖安装:

replaceSystemPackageLI函数实现系统APK的覆盖安装,核心是要先清除已安装信息,否则会提示APK已存在

实现已安装系统APK数据清除的代码

  int reparseFlags = PackageParser.PARSE_IS_SYSTEM
				    | PackageParser.PARSE_IS_SYSTEM_DIR;
	    int scanFlags = SCAN_NO_PATHS | SCAN_DEFER_DEX | SCAN_BOOTING | SCAN_INITIAL;
	    File apk_file = new File(originPath);
	    /*****Replace system app start*****/
	    if(replace) {
		    PackageParser pp = new PackageParser();
		    pp.setSeparateProcesses(mSeparateProcesses);
		    pp.setDisplayMetrics(mMetrics);
		    final PackageParser.Package pkg;
		    try {
			pkg = pp.parsePackage(apk_file, reparseFlags);
		    }catch (PackageParserException e) {
			res.setError("Failed parse during installPackageLI", e);
			return;
		    }
		    String packageName = pkg.packageName;
		    PackageParser.Package oldPkg;
		    PackageSetting oldPkgSetting;
		    
		    // reader
		    synchronized (mPackages) {
			oldPkg = mPackages.get(packageName);
			oldPkgSetting = mSettings.mPackages.get(packageName);
			if((oldPkg == null) || (oldPkg.applicationInfo == null) ||
			    (oldPkgSetting == null)) {
			res.setError(INSTALL_FAILED_REPLACE_COULDNT_DELETE,
				"Couldn't find package:" + packageName + " information");
			return;
			}
		    }
		    
		    killApplication(packageName, oldPkg.applicationInfo.uid, "replace sys pkg");
		    
		    res.removedInfo.uid = oldPkg.applicationInfo.uid;
		    res.removedInfo.removedPackage = packageName;
		    // Remove existing system package
		    removePackageLI(oldPkgSetting, true);
		    // writer
		    /* synchronized (mPackages) {
			disabledSystem = mSettings.disableSystemPackageLPw(packageName);
			if (!disabledSystem && deletedPackage != null) {
			// We didn't need to disable the .apk as a current system package,
			// which means we are replacing another update that is already
			// installed.  We need to make sure to delete the older one's .apk.
			res.removedInfo.args = createInstallArgsForExisting(0,
				deletedPackage.applicationInfo.getCodePath(),
				deletedPackage.applicationInfo.getResourcePath(),
				getAppDexInstructionSets(deletedPackage.applicationInfo));
			} else {
			res.removedInfo.args = null;
			}
		    } */
		    
		    // Successfully disabled the old package. Now proceed with re-installation
		    deleteCodeCacheDirsLI(pkg.volumeUuid, packageName); 
	    }
	    /*****Replace system app end*****/
	    try {
	        //setApplicationEnabledSetting(newPackage.packageName,PackageManager.COMPONENT_ENABLED_STATE_DISABLED,
	        //0,userId,null);
	        PackageParser.Package newPackage = scanPackageLI(apk_file, reparseFlags, scanFlags, 0L, null);
	        updateSettingsLI(newPackage, installerPackageName, null, null, null, res, new UserHandle(userId));
	        setApplicationEnabledSetting(newPackage.packageName,PackageManager.COMPONENT_ENABLED_STATE_ENABLED,
	        PackageManager.DONT_KILL_APP,userId,null);
	    } catch (PackageManagerException e) {
	        Log.e(TAG, "lvjiong Failed to parse original system package: "
	    	    + e.getMessage());
	    } 

 

PMS(Project Management System,项目管理系统)中安装APK时,通常会检查设备可用的存储空间来确定能否继续安装。以下是一个常见的步骤,你可以通过Android API来实现这一功能: 1. **获取可用存储空间信息**:首先,你需要访问`Context`对象的`getExternalFilesDir()`或`getExternalCacheDir()`方法获取外部存储空间的路径。然后,你可以读取该目录的`File`实例的`length()`属性来获取可用空间的总量。 ```java public long getAvailableSpace() { File externalStorageDir = Environment.getExternalStorageDirectory(); if (externalStorageDir != null && externalStorageDir.canWrite()) { return externalStorageDir.getFreeSpace(); } else { // 如果外部存储不可写,检查内部存储 File appCacheDir = context.getCacheDir(); return appCacheDir.getFreeSpace(); } } ``` 2. **比较APK大小与可用空间**:计算要安装APK文件的大小,通常是通过读取APK文件本身的信息,例如从`Uri`获取。如果APK大小加上现有的应用数量(因为其他应用也需要空间),大于可用空间,则认为无法安装。 ```java long apkSizeInBytes = getApkFileSizeFromPath(apkFilePath); // 获取APK的实际大小 long totalRequiredSpace = apkSizeInBytes + getEstimatedAppSumSize(); // 总需空间(APK + 已有应用占用) if (totalRequiredSpace > getAvailableSpace()) { // 显示存储空间不足提示 Toast.makeText(context, "Insufficient storage for installation", Toast.LENGTH_SHORT).show(); return false; // 返回false表示无法安装 } else { // 其他安装逻辑... return true; } ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Free飝Fly

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值