android 中使一个system/app下的系统应用开机过程不去安装

android 系统中使一个系统应用(system/app下的应用)开机过程不再安装,但是依然存在在system/app下,等到某种条件下需要安装时,任然可以安装。

需求:

在android 系统中开发的所有的应用,不全都是给用户使用的,有的应用在前期,例如在卖场中展示使用,但是到用户手上后,又不需要它了。
这里有两种方案,一是将应用安装到data 底下。出厂后卸载。二是依然将应用以系统应用的方式,打包在system/app下,出厂后,使其不再安装,而到想使用的时候,再通过某种开关打开一个flag,然后重启,这个应用就可以再次被安装了。这里主要来说第二种方案.
ps:当然还有一种方案,就是可以动态的通过某个条件去隐藏disable 这个apk。具体可以参考我这边文章

具体做法

这里我们介绍下在开机过程中动态的去选择安装或者不安装它。
应用安装的过程是在PMS 中来做的。熟悉PMS的应该知道,android 系统在开机的时候会走到PMS这一流程中来,然后会在PackageManagerService.java 中去遍历安装系统预制的apk。当然这也就是为什么我们adb push 一个apk到system下,然后重启后,这个apk会在开机后自动安装好的原因了。

frameworks / base/services/core/java/com/android/server/pm/PackageManagerService.java
private void scanDirLI(File scanDir, int parseFlags, int scanFlags, long currentTime) {
        final File[] files = scanDir.listFiles();
        if (ArrayUtils.isEmpty(files)) {
            Log.d(TAG, "No files in app dir " + scanDir);
            return;
        }

        if (DEBUG_PACKAGE_SCANNING) {
            Log.d(TAG, "Scanning app dir " + scanDir + " scanFlags=" + scanFlags
                    + " flags=0x" + Integer.toHexString(parseFlags));
        }
        try (ParallelPackageParser parallelPackageParser = new ParallelPackageParser(
                mSeparateProcesses, mOnlyCore, mMetrics, mCacheDir,
                mParallelPackageParserCallback)) {
            // Submit files for parsing in parallel
            int fileCount = 0;
			String isNetflix = Utils.getConfigDataIsSupportNetflix();
            for (File file : files) {
                final boolean isPackage = (isApkFile(file) || file.isDirectory())
                        && !PackageInstallerService.isStageName(file.getName());
				if(file.toString().equals("/system/app/QQ")) {      // 1  
					if(动态安装与否的某个条件)               // 2
					{
	                    // Ignore install Netflix packages
	                    continue;
					}
                }
				if (!isPackage) {
                    // Ignore entries which are not packages
                    continue;
                }
                parallelPackageParser.submit(file, parseFlags);
                fileCount++;
            }

            // Process results one by one
            for (; fileCount > 0; fileCount--) {
                ParallelPackageParser.ParseResult parseResult = parallelPackageParser.take();
                Throwable throwable = parseResult.throwable;
                int errorCode = PackageManager.INSTALL_SUCCEEDED;

                if (throwable == null) {
                    // TODO(toddke): move lower in the scan chain
                    // Static shared libraries have synthetic package names
                    if (parseResult.pkg.applicationInfo.isStaticSharedLibrary()) {
                        renameStaticSharedLibraryPackage(parseResult.pkg);
                    }
                    try {
                        if (errorCode == PackageManager.INSTALL_SUCCEEDED) {
                            scanPackageChildLI(parseResult.pkg, parseFlags, scanFlags,
                                    currentTime, null);
                        }
                    } catch (PackageManagerException e) {
                        errorCode = e.error;
                        Slog.w(TAG, "Failed to scan " + parseResult.scanFile + ": " + e.getMessage());
                    }
                } else if (throwable instanceof PackageParser.PackageParserException) {
                    PackageParser.PackageParserException e = (PackageParser.PackageParserException)
                            throwable;
                    errorCode = e.error;
                    Slog.w(TAG, "Failed to parse " + parseResult.scanFile + ": " + e.getMessage());
                } else {
                    throw new IllegalStateException("Unexpected exception occurred while parsing "
                            + parseResult.scanFile, throwable);
                }

                // Delete invalid userdata apps
                if ((scanFlags & SCAN_AS_SYSTEM) == 0 &&
                        errorCode != PackageManager.INSTALL_SUCCEEDED) {
                    logCriticalInfo(Log.WARN,
                            "Deleting invalid package at " + parseResult.scanFile);
                    removeCodePathLI(parseResult.scanFile);
                }
            }
        }
    }

在以上的文件中,scanDirLI 方法主要是遍历系统中的apk的,我们可以在它遍历的过程中,把它过滤掉,这样这个apk就不安装了。在1处,我们以QQ.apk 为例。假如有这个apk,并且符合我们不安装的条件,如2处。我们就continue 掉它。

到此。这个apk在开机后就不会被安装了。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

假装多好123

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

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

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

打赏作者

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

抵扣说明:

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

余额充值