Android 11.0 PackageManagerService(二)APK扫描过程

本文深入剖析了Android系统中PackageManagerService如何扫描系统路径下的所有APK文件,从Android10.0到Android11.0的路径变化,以及 APK 的扫描过程。首先,通过遍历系统所有分区并调用scanDirTracedLI方法进行扫描。接着,解析过程中,使用ParallelPackageParser队列收集系统apk,逐个进行PackageParser解析。最后,解析完成后,进行校验、签名检查和更新操作。整个过程涉及系统分区、文件遍历、XML解析和包管理等多个关键步骤。

PackageManagerService的构造函数中调用了scanDirTracedLI方法来扫描某个目录的apk文件。

1. 扫描路径

在Android 10.0中,PKMS主要扫描以下路径的APK信息:

/vendor/overlay
/product/overlay
/product_services/overlay
/odm/overlay
/oem/overlay
/system/framework
/system/priv-app
/system/app
/vendor/priv-app
/vendor/app
/odm/priv-app
/odm/app
/oem/app
/oem/priv-app
/product/priv-app
/product/app
/product_services/priv-app
/product_services/app
/product_services/priv-app

然而在Android 11.0中,PKMS扫描的路径虽然和Android 10.0中的不完全相同但是也是扫描的所有的路径。从以下注释中也可以看出

// Android 10.0中执行scanDirTracedLI方法前的注释


// Collect vendor/product/product_services overlay packages. (Do this before scanning
            // any apps.)


// Android 11.0中执行scanDirTracedLI方法前的注释

// Collect vendor/product/system_ext overlay packages. (Do this before scanning
            // any apps.)

现在我们从源码中去找一下扫描的是所有路径的依据:

for (int i = mDirsToScanAsSystem.size() - 1; i >= 0; i--) {
                final ScanPartition partition = mDirsToScanAsSystem.get(i);
                if (partition.getOverlayFolder() == null) {
                    continue;
                }
                scanDirTracedLI(partition.getOverlayFolder(), systemParseFlags,
                        systemScanFlags | partition.scanFlag, 0,
                        packageParser, executorService);
}

我们发现,此处遍历了一个mDirToScanAsSystem集合。

在执行scanTracedLI方法前有这样一段代码:

for (int i = 0; i < activeApexInfos.size(); i++) {
            final ScanPartition scanPartition =         
     resolveApexToScanPartition(activeApexInfos.get(i));
     if (scanPartition != null) {
            scanPartitions.add(scanPartition);
     }
}

mDirsToScanAsSystem = new ArrayList<>();
mDirsToScanAsSystem.addAll(SYSTEM_PARTITIONS);
mDirsToScanAsSystem.addAll(scanPartitions);

看一下resolveApexToScanPartition方法的源码:

private static @Nullable ScanPartition resolveApexToScanPartition(
            ApexManager.ActiveApexInfo apexInfo) {
        for (int i = 0, size = SYSTEM_PARTITIONS.size(); i < size; i++) {
            ScanPartition sp = SYSTEM_PARTITIONS.get(i);
            if (apexInfo.preInstalledApexPath.getAbsolutePath().startsWith(
                    sp.getFolder().getAbsolutePath())) {
                return new ScanPartition(apexInfo.apexDirectory, sp, SCAN_AS_APK_IN_APEX);
            }
        }
        return null;
    }

我们看到新建了一个ScanPartition对象,

public ScanPartition(@NonNull SystemPartition partition) {
            super(partition);
            scanFlag = scanFlagForPartition(partition);
        }

在构造方法中调用了scanFlagForPartition方法,代码如下:

private static int scanFlagForPartition(PackagePartitions.SystemPartition partition) {
            switch (partition.type) {
                case PackagePartitions.PARTITION_SYSTEM:
                    return 0;
                case PackagePartitions.PARTITION_VENDOR:
                    return SCAN_AS_VENDOR;
                case PackagePartitions.PARTITION_ODM:
                    return SCAN_AS_ODM;
                case PackagePartitions.PARTITION_OEM:
                    return SCAN_AS_OEM;
                case PackagePartitions.PARTITION_PRODUCT:
                    return SCAN_AS_PRODUCT;
                case PackagePartitions.PARTITION_SYSTEM_EXT:
                    return SCAN_AS_SYSTEM_EXT;
                default:
                    throw new IllegalStateException("Unable to determine scan flag for "
                            + partition.getFolder());
            }
        }

而上面的代码:

mDirsToScanAsSystem.addAll(SYSTEM_PARTITIONS);

中SYSTEM_PARTITIONS的初始化代码如下:

/**
     * The list of all system partitions that may contain packages in ascending order of
     * specificity (the more generic, the earlier in the list a partition appears).
     */
    @VisibleForTesting(visibility = Visibility.PRIVATE)
    public static final List<ScanPartition> SYSTEM_PARTITIONS = Collections.unmodifiableList(
            PackagePartitions.getOrderedPartitions(ScanPartition::new));

注释表示返回的就是系统的所有分区。接着看一下PackagePartitions类中的getOrderdPartitions方法的代码:

/**
     * Returns a list in which the elements are products of the specified function applied to the
     * list of {@link #SYSTEM_PARTITIONS} in increasing specificity order.
     */
    public static <T> ArrayList<T> getOrderedPartitions(
            @NonNull Function<SystemPartition, T> producer) {
        final ArrayList<T> out = new ArrayList<>();
        for (int i = 0, n = SYSTEM_PARTITIONS.size(); i < n; i++) {
            final T v = producer.apply(SYSTEM_PARTITIONS.get(i));
            if (v != null)  {
                out.add(v);
            }
        }
        return out;
    }

SYSTEM_PARTITIONS的初始化代码:

 /**
     * The list of all system partitions that may contain packages in ascending order of
     * specificity (the more generic, the earlier in the list a partition appears).
     */
    private static final ArrayList<SystemPartition> SYSTEM_PARTITIONS =
            new ArrayList<>(Arrays.asList(
                    new SystemPartition(Environment.getRootDirectory(), PARTITION_SYSTEM,
                            true /* containsPrivApp */, false /* containsOverlay */),
                    new SystemPartition(Environment.getVendorDirectory(), PARTITION_VENDOR,
                            true /* containsPrivApp */, true /* containsOverlay */),
                    new SystemPartition(Environment.getOdmDirectory(), PARTITION_ODM,
                            true /* containsPrivApp */, true /* containsOverlay */),
                    new SystemPartition(Environment.getOemDirectory(), 
评论 11
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值