PackageManagerService 深入理解Android 卷2 学习笔记

news2024/11/27 22:24:28

PackageManagerService是Android核心服务之一,负责系统中Package的管理,应用程序的安装、卸载、信息查询等。

1、初识PMS

PMS由SystemServer创建:
SystemServer的run函数调用startBootstrapServices,startBootstrapServices调用PackageManagerService.main函数

frameworks/base/services/java/com/android/server/SystemServer.java


        t.traceBegin("StartPackageManagerService");
        try {
            Watchdog.getInstance().pauseWatchingCurrentThread("packagemanagermain");
            mPackageManagerService = PackageManagerService.main(mSystemContext, installer,
                    mFactoryTestMode != FactoryTest.FACTORY_TEST_OFF, mOnlyCore);
        } finally {
            Watchdog.getInstance().resumeWatchingCurrentThread("packagemanagermain");
        }

2、PMS的main函数分析

frameworks/base/services/core/java/com/android/server/pm/PackageManagerService.java

    public static PackageManagerService main(Context context, Installer installer,
            boolean factoryTest, boolean onlyCore) {
        // Self-check for initial settings.
        PackageManagerServiceCompilerMapping.checkProperties();
        final TimingsTraceAndSlog t = new TimingsTraceAndSlog(TAG + "Timing",
                Trace.TRACE_TAG_PACKAGE_MANAGER);
        t.traceBegin("create package manager");
        final Object lock = new Object();
        final Object installLock = new Object();

        Injector injector = new Injector(
                context, lock, installer, installLock, new PackageAbiHelperImpl(),
                (i, pm) ->
                        new ComponentResolver(i.getUserManagerService(), pm.mPmInternal, lock),
                (i, pm) ->
                        PermissionManagerService.create(context, lock),
                (i, pm) ->
                        new UserManagerService(context, pm,
                                new UserDataPreparer(installer, installLock, context, onlyCore),
                                lock),
                (i, pm) ->
                        new Settings(Environment.getDataDirectory(),
                                i.getPermissionManagerServiceInternal().getPermissionSettings(),
                                lock),
                new Injector.LocalServicesProducer<>(ActivityTaskManagerInternal.class),
                new Injector.LocalServicesProducer<>(ActivityManagerInternal.class),
                new Injector.LocalServicesProducer<>(DeviceIdleInternal.class),
                new Injector.LocalServicesProducer<>(StorageManagerInternal.class),
                new Injector.LocalServicesProducer<>(NetworkPolicyManagerInternal.class),
                new Injector.LocalServicesProducer<>(PermissionPolicyInternal.class),
                new Injector.LocalServicesProducer<>(DeviceStorageMonitorInternal.class),
                new Injector.SystemServiceProducer<>(DisplayManager.class),
                new Injector.SystemServiceProducer<>(StorageManager.class),
                new Injector.SystemServiceProducer<>(AppOpsManager.class),
                (i, pm) -> AppsFilter.create(pm.mPmInternal, i),
                (i, pm) -> (PlatformCompat) ServiceManager.getService("platform_compat"));

        PackageManagerService m = new PackageManagerService(injector, onlyCore, factoryTest);
        t.traceEnd(); // "create package manager"

        injector.getCompatibility().registerListener(SELinuxMMAC.SELINUX_LATEST_CHANGES,
                packageName -> {
                    synchronized (m.mInstallLock) {
                        final AndroidPackage pkg;
                        final PackageSetting ps;
                        final SharedUserSetting sharedUser;
                        final String oldSeInfo;
                        synchronized (m.mLock) {
                            ps = m.mSettings.getPackageLPr(packageName);
                            if (ps == null) {
                                Slog.e(TAG, "Failed to find package setting " + packageName);
                                return;
                            }
                            pkg = ps.pkg;
                            sharedUser = ps.getSharedUser();
                            oldSeInfo = AndroidPackageUtils.getSeInfo(pkg, ps);
                        }

                        if (pkg == null) {
                            Slog.e(TAG, "Failed to find package " + packageName);
                            return;
                        }
                        final String newSeInfo = SELinuxMMAC.getSeInfo(pkg, sharedUser,
                                m.mInjector.getCompatibility());

                        if (!newSeInfo.equals(oldSeInfo)) {
                            Slog.i(TAG, "Updating seInfo for package " + packageName + " from: "
                                    + oldSeInfo + " to: " + newSeInfo);
                            ps.getPkgState().setOverrideSeInfo(newSeInfo);
                            m.prepareAppDataAfterInstallLIF(pkg);
                        }
                    }
                });

        m.installWhitelistedSystemPackages();
        ServiceManager.addService("package", m);
        final PackageManagerNative pmn = m.new PackageManagerNative();
        ServiceManager.addService("package_native", pmn);
        return m;
    }

main是应用程序包管理器的入口点,用于初始化和启动PackageManagerService服务,包括依赖注入、注册监听器、安装系统包等,并将服务添加到系统服务中。
main中执行了PMS的构造函数,PMS的构造函数进行了许多重体力活,这也是Android启动速度慢的原因之一。

PMS主要功能:扫描Android系统中几个目标文件夹中的apk,从而构建合适的数据结构以管理诸如Package信息、四大组件信息、权限信息等各种信息。抽象的看,PMS是一个加工厂,它解析实际的物理文件(APK文件)以生成符合自己要求的产品。例如,PMS将解析APK包的AndroidManifest.xml,并根据其中声明的Activity标签来创建于此对应的对象来加以保管。
PMS工作流程相对简单,复杂的是其中用于保存各种信息的数据结构和他们之间的关系,以及影响最终结果的策略控制。

卷2使用的是Android4的代码,已经是很古老的了,细节上跟现在的新版本Android代码可能有一些区别。但整体的功能应该是一致的。

2.1构造函数分析之前期准备工作

frameworks/base/services/core/java/com/android/server/pm/PackageManagerService.java

     public PackageManagerService(Injector injector, boolean onlyCore, boolean factoryTest) {
        PackageManager.disableApplicationInfoCache();
        PackageManager.disablePackageInfoCache();

        // Avoid invalidation-thrashing by preventing cache invalidations from causing property
        // writes if the cache isn't enabled yet.  We re-enable writes later when we're
        // done initializing.
        PackageManager.corkPackageInfoCache();

        final TimingsTraceAndSlog t = new TimingsTraceAndSlog(TAG + "Timing",
                Trace.TRACE_TAG_PACKAGE_MANAGER);
        mPendingBroadcasts = new PendingPackageBroadcasts();

        mInjector = injector;
        mInjector.bootstrap(this);
        mLock = injector.getLock();
        mInstallLock = injector.getInstallLock();
        LockGuard.installLock(mLock, LockGuard.INDEX_PACKAGES);
        EventLog.writeEvent(EventLogTags.BOOT_PROGRESS_PMS_START,
                SystemClock.uptimeMillis());

        if (mSdkVersion <= 0) {
            Slog.w(TAG, "**** ro.build.version.sdk not set!");
        }

        mContext = injector.getContext();
        mFactoryTest = factoryTest;
        mOnlyCore = onlyCore;
        mMetrics = new DisplayMetrics();
        mInstaller = injector.getInstaller();

        // Create sub-components that provide services / data. Order here is important.
        t.traceBegin("createSubComponents");

        // Expose private service for system components to use.
        mPmInternal = new PackageManagerInternalImpl();
        LocalServices.addService(PackageManagerInternal.class, mPmInternal);
        mUserManager = injector.getUserManagerService();
        mComponentResolver = injector.getComponentResolver();
        mPermissionManager = injector.getPermissionManagerServiceInternal();
        mSettings = injector.getSettings();
        mPermissionManagerService = (IPermissionManager) ServiceManager.getService("permissionmgr");
        mIncrementalManager =
                (IncrementalManager) mContext.getSystemService(Context.INCREMENTAL_SERVICE);
        PlatformCompat platformCompat = mInjector.getCompatibility();
        mPackageParserCallback = new PackageParser2.Callback() {
            @Override
            public boolean isChangeEnabled(long changeId, @NonNull ApplicationInfo appInfo) {
                return platformCompat.isChangeEnabled(changeId, appInfo);
            }

            @Override
            public boolean hasFeature(String feature) {
                return PackageManagerService.this.hasSystemFeature(feature, 0);
            }
        };

        // CHECKSTYLE:ON IndentationCheck
        t.traceEnd();

        t.traceBegin("addSharedUsers");
        mSettings.addSharedUserLPw("android.uid.system", Process.SYSTEM_UID,
                ApplicationInfo.FLAG_SYSTEM, ApplicationInfo.PRIVATE_FLAG_PRIVILEGED);
        mSettings.addSharedUserLPw("android.uid.phone", RADIO_UID,
                ApplicationInfo.FLAG_SYSTEM, ApplicationInfo.PRIVATE_FLAG_PRIVILEGED);
        mSettings.addSharedUserLPw("android.uid.log", LOG_UID,
                ApplicationInfo.FLAG_SYSTEM, ApplicationInfo.PRIVATE_FLAG_PRIVILEGED);
        mSettings.addSharedUserLPw("android.uid.nfc", NFC_UID,
                ApplicationInfo.FLAG_SYSTEM, ApplicationInfo.PRIVATE_FLAG_PRIVILEGED);
        mSettings.addSharedUserLPw("android.uid.bluetooth", BLUETOOTH_UID,
                ApplicationInfo.FLAG_SYSTEM, ApplicationInfo.PRIVATE_FLAG_PRIVILEGED);
        mSettings.addSharedUserLPw("android.uid.shell", SHELL_UID,
                ApplicationInfo.FLAG_SYSTEM, ApplicationInfo.PRIVATE_FLAG_PRIVILEGED);
        mSettings.addSharedUserLPw("android.uid.se", SE_UID,
                ApplicationInfo.FLAG_SYSTEM, ApplicationInfo.PRIVATE_FLAG_PRIVILEGED);
        mSettings.addSharedUserLPw("android.uid.networkstack", NETWORKSTACK_UID,
                ApplicationInfo.FLAG_SYSTEM, ApplicationInfo.PRIVATE_FLAG_PRIVILEGED);
        t.traceEnd();
        }

前半段主要进行了一些初始化和创建子组件的工作。

在传入的参数中Injector是一个用于依赖注入的辅助类或接口。在这段代码中,Injector被用于创建和初始化PackageManagerService类的实例。
依赖注入是一种设计模式,用于解耦组件之间的依赖关系。通过依赖注入,一个对象可以通过构造函数、方法参数或属性注入的方式获取它所依赖的其他对象,而不需要自己创建或管理这些依赖对象。
在这段代码中,Injector负责创建和提供PackageManagerService所需的依赖对象,例如上下文(Context)、锁(Lock)、安装器(Installer)等。它可能是一个具体的类,也可能是一个接口,具体实现由代码的其他部分提供。
通过使用Injector,PackageManagerService类可以将对这些依赖对象的创建和管理的责任委托给外部,从而使代码更加模块化和可测试。这种依赖注入的方式可以提高代码的可维护性和可扩展性。
在PMS的main函数中创建过Injector

在这里插入图片描述
刚进入构造函数,就会遇到第一个较为复杂的数据结构Settings和它的addSharedUserLPw函数,Settings的作用是管理Android系统运行过程中的一些设置信息

初识Settings

注意,Android中有多个Settings,注意区分。

        mSettings.addSharedUserLPw("android.uid.system", Process.SYSTEM_UID,
                ApplicationInfo.FLAG_SYSTEM, ApplicationInfo.PRIVATE_FLAG_PRIVILEGED);

以这段代码为例:
这个方法接受四个参数:

  1. name:共享用户的名称,这里是"android.uid.system",表示系统级别的共享用户。

  2. uid:共享用户的用户ID,这里是Process.SYSTEM_UID,表示系统级别的用户ID。

  3. pkgFlags:共享用户的包标志,这里是ApplicationInfo.FLAG_SYSTEM,表示该共享用户是系统级别的。

  4. pkgPrivateFlags:共享用户的私有包标志,这里是ApplicationInfo.PRIVATE_FLAG_PRIVILEGED,表示该共享用户是特权级别的。

UID和GID
UID为用户ID缩写,GID为用户组ID缩写,这两个概念与Linux系统中进程的权限管理有关,一般来说,每个进程都会有一个对应的UID(表示该进程属于哪个用户,不同用户有不同权限),一个进程可以分属不同的用户组
在Android平台中,系统定义的UID和GID在Process.java中

frameworks/base/services/core/java/com/android/server/pm/Settings.java

    SharedUserSetting addSharedUserLPw(String name, int uid, int pkgFlags, int pkgPrivateFlags) {
        SharedUserSetting s = mSharedUsers.get(name);
        if (s != null) {
            if (s.userId == uid) {
                return s;
            }
            PackageManagerService.reportSettingsProblem(Log.ERROR,
                    "Adding duplicate shared user, keeping first: " + name);
            return null;
        }
        s = new SharedUserSetting(name, pkgFlags, pkgPrivateFlags);
        s.userId = uid;
        if (registerExistingAppIdLPw(uid, s, name)) {
            mSharedUsers.put(name, s);
            return s;
        }
        return null;
    }

这个方法用于向共享用户设置中添加共享用户。它检查是否存在相同的共享用户,如果存在则返回已存在的共享用户对象,如果不存在则创建新的共享用户对象并添加到设置中。这个方法会向mSharedUsers添加一条数据
由上面的方法可知,Settings中有一个mSharedUsers成员,存储的是字符串和SharedUSerSetting键值对
SharedUserSetting分析
在apk的AndroidManifest.xml中通过在mainfest标签里添加android.sharedUserId="android.uid.system"来共享UID,从而使apk获取系统权限。
在这里插入图片描述
多个声明了同一种sharedUserId的apk可以共享彼此的数据,并且可以运行在同一进程中。
更重要的是,通过声明特定的sharedUserId,该apk所在进程将被赋予指定的UID

根据以上内容思考,如何组织数据结构来包含以上内容:
1.XML中sharedUserId是指定的字符串来描述UID,数据结构中需要有一个这样的字符串来将代码和XML的属性联系起来。
2.uid是整数,数据结构中需要有一个整型变量
3.多个Package可以声明同一个UID,因此该数据结构必然会保存那些声明了相同sharedUserId的package的某些信息

frameworks/base/services/core/java/com/android/server/pm/SharedUserSetting.java

public final class SharedUserSetting extends SettingBase {
    final String name;

    int userId;

    // flags that are associated with this uid, regardless of any package flags
    int uidFlags;
    int uidPrivateFlags;

    // The lowest targetSdkVersion of all apps in the sharedUserSetting, used to assign seinfo so
    // that all apps within the sharedUser run in the same selinux context.
    int seInfoTargetSdkVersion;

    final ArraySet<PackageSetting> packages = new ArraySet<>();

    final PackageSignatures signatures = new PackageSignatures();
    Boolean signaturesChanged;

    ArrayMap<String, ParsedProcess> processes;
...
}
  • name:共享用户的名称。

  • userId:共享用户的用户ID。

  • uidFlags:与该用户ID关联的标志,不考虑任何包的标志。

  • uidPrivateFlags:与该用户ID关联的私有标志。

  • seInfoTargetSdkVersion:共享用户中所有应用程序的最低targetSdkVersion,用于分配seinfo,以便共享用户中的所有应用程序在相同的SELinux上下文中运行。

  • packages:一个ArraySet,用于存储与该共享用户关联的包设置PackageSetting。

  • signatures:一个PackageSignatures对象,用于存储与该共享用户关联的包的签名信息。

  • signaturesChanged:一个Boolean值,表示与该共享用户关联的包的签名是否发生了变化。

  • processes:一个ArrayMap,用于存储与该共享用户关联的进程信息。

这里是引用PackageSetting是用于存储和管理应用程序包的设置信息的类。
在Android系统中,每个应用程序都有一个对应的PackageSetting对象,用于存储与该应用程序包相关的各种设置和属性,例如包名、版本号、签名信息、权限信息、安装路径等。
PackageSetting类包含了应用程序包的各种属性和成员变量,例如包名、用户ID、应用程序信息、权限信息、签名信息、安装路径等。它还提供了一些方法和接口,用于获取和设置这些属性,以及进行与应用程序包相关的操作,例如安装、卸载、更新等。

XML文件扫描

在卷2的Android4中,PackageManagerService的构造中会直接调用readPermissions方法来读取权限。而Android11中,这个方法在SystemConfig中,叫做readAllPermissions。
PackageManagerService创建了SystemConfig。
在这里插入图片描述

SystemConfig的构造方法中调用了readAllPermissions
frameworks/base/core/java/com/android/server/SystemConfig.java

    SystemConfig() {
        TimingsTraceLog log = new TimingsTraceLog(TAG, Trace.TRACE_TAG_SYSTEM_SERVER);
        log.traceBegin("readAllPermissions");
        try {
            readAllPermissions();
        } finally {
            log.traceEnd();
        }
    }
    private void readAllPermissions() {
        // Read configuration from system
        readPermissions(Environment.buildPath(
                Environment.getRootDirectory(), "etc", "sysconfig"), ALLOW_ALL);

        // Read configuration from the old permissions dir
        readPermissions(Environment.buildPath(
                Environment.getRootDirectory(), "etc", "permissions"), ALLOW_ALL);

        // Vendors are only allowed to customize these
        int vendorPermissionFlag = ALLOW_LIBS | ALLOW_FEATURES | ALLOW_PRIVAPP_PERMISSIONS
                | ALLOW_ASSOCIATIONS;
        if (Build.VERSION.FIRST_SDK_INT <= Build.VERSION_CODES.O_MR1) {
            // For backward compatibility
            vendorPermissionFlag |= (ALLOW_PERMISSIONS | ALLOW_APP_CONFIGS);
        }
        readPermissions(Environment.buildPath(
                Environment.getVendorDirectory(), "etc", "sysconfig"), vendorPermissionFlag);
        readPermissions(Environment.buildPath(
                Environment.getVendorDirectory(), "etc", "permissions"), vendorPermissionFlag);

        String vendorSkuProperty = SystemProperties.get(VENDOR_SKU_PROPERTY, "");
        if (!vendorSkuProperty.isEmpty()) {
            String vendorSkuDir = "sku_" + vendorSkuProperty;
            readPermissions(Environment.buildPath(
                    Environment.getVendorDirectory(), "etc", "sysconfig", vendorSkuDir),
                    vendorPermissionFlag);
            readPermissions(Environment.buildPath(
                    Environment.getVendorDirectory(), "etc", "permissions", vendorSkuDir),
                    vendorPermissionFlag);
        }

        // Allow ODM to customize system configs as much as Vendor, because /odm is another
        // vendor partition other than /vendor.
        int odmPermissionFlag = vendorPermissionFlag;
        readPermissions(Environment.buildPath(
                Environment.getOdmDirectory(), "etc", "sysconfig"), odmPermissionFlag);
        readPermissions(Environment.buildPath(
                Environment.getOdmDirectory(), "etc", "permissions"), odmPermissionFlag);

        String skuProperty = SystemProperties.get(SKU_PROPERTY, "");
        if (!skuProperty.isEmpty()) {
            String skuDir = "sku_" + skuProperty;

            readPermissions(Environment.buildPath(
                    Environment.getOdmDirectory(), "etc", "sysconfig", skuDir), odmPermissionFlag);
            readPermissions(Environment.buildPath(
                    Environment.getOdmDirectory(), "etc", "permissions", skuDir),
                    odmPermissionFlag);
        }

        // Allow OEM to customize these
        int oemPermissionFlag = ALLOW_FEATURES | ALLOW_OEM_PERMISSIONS | ALLOW_ASSOCIATIONS;
        readPermissions(Environment.buildPath(
                Environment.getOemDirectory(), "etc", "sysconfig"), oemPermissionFlag);
        readPermissions(Environment.buildPath(
                Environment.getOemDirectory(), "etc", "permissions"), oemPermissionFlag);

        // Allow Product to customize all system configs
        readPermissions(Environment.buildPath(
                Environment.getProductDirectory(), "etc", "sysconfig"), ALLOW_ALL);
        readPermissions(Environment.buildPath(
                Environment.getProductDirectory(), "etc", "permissions"), ALLOW_ALL);

        // Allow /system_ext to customize all system configs
        readPermissions(Environment.buildPath(
                Environment.getSystemExtDirectory(), "etc", "sysconfig"), ALLOW_ALL);
        readPermissions(Environment.buildPath(
                Environment.getSystemExtDirectory(), "etc", "permissions"), ALLOW_ALL);

        // Skip loading configuration from apex if it is not a system process.
        if (!isSystemProcess()) {
            return;
        }
        // Read configuration of libs from apex module.
        // TODO: Use a solid way to filter apex module folders?
        for (File f: FileUtils.listFilesOrEmpty(Environment.getApexDirectory())) {
            if (f.isFile() || f.getPath().contains("@")) {
                continue;
            }
            readPermissions(Environment.buildPath(f, "etc", "permissions"), ALLOW_LIBS);
        }
    }
    
        @VisibleForTesting
    public void readPermissions(File libraryDir, int permissionFlag) {
        // Read permissions from given directory.
        if (!libraryDir.exists() || !libraryDir.isDirectory()) {
            if (permissionFlag == ALLOW_ALL) {
                Slog.w(TAG, "No directory " + libraryDir + ", skipping");
            }
            return;
        }
        if (!libraryDir.canRead()) {
            Slog.w(TAG, "Directory " + libraryDir + " cannot be read");
            return;
        }

        // Iterate over the files in the directory and scan .xml files
        File platformFile = null;
        for (File f : libraryDir.listFiles()) {
            if (!f.isFile()) {
                continue;
            }

            // We'll read platform.xml last
            if (f.getPath().endsWith("etc/permissions/platform.xml")) {
                platformFile = f;
                continue;
            }

            if (!f.getPath().endsWith(".xml")) {
                Slog.i(TAG, "Non-xml file " + f + " in " + libraryDir + " directory, ignoring");
                continue;
            }
            if (!f.canRead()) {
                Slog.w(TAG, "Permissions library file " + f + " cannot be read");
                continue;
            }

            readPermissionsFromXml(f, permissionFlag);
        }

        // Read platform permissions last so it will take precedence
        if (platformFile != null) {
            readPermissionsFromXml(platformFile, permissionFlag);
        }
    }

readAllPermissions方法读取了各个目录下的权限配置文件,并进行相应的权限设置。
readPermissions()用于从给定的目录中读取权限配置文件,并进行相应的处理。
注意:在readPermissions()方法中有个逻辑,如果文件的路径以"etc/permissions/platform.xml"结尾,表示这是platform.xml文件,代码会将其保存在platformFile变量中,并继续遍历下一个文件, 最后,代码会读取platformFile中的权限配置,以确保它具有最高的优先级。
以下为Android11,system/etc/permissions/platform.xml的内容:

<?xml version="1.0" encoding="utf-8"?>
<!-- Copyright (C) 2008 The Android Open Source Project

     Licensed under the Apache License, Version 2.0 (the "License");
     you may not use this file except in compliance with the License.
     You may obtain a copy of the License at

          http://www.apache.org/licenses/LICENSE-2.0

     Unless required by applicable law or agreed to in writing, software
     distributed under the License is distributed on an "AS IS" BASIS,
     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     See the License for the specific language governing permissions and
     limitations under the License.
-->

<!-- This file is used to define the mappings between lower-level system
     user and group IDs and the higher-level permission names managed
     by the platform.

     Be VERY careful when editing this file!  Mistakes made here can open
     big security holes.
-->
<permissions>

    <!-- ================================================================== -->
    <!-- ================================================================== -->
    <!-- ================================================================== -->

    <!-- The following tags are associating low-level group IDs with
         permission names.  By specifying such a mapping, you are saying
         that any application process granted the given permission will
         also be running with the given group ID attached to its process,
         so it can perform any filesystem (read, write, execute) operations
         allowed for that group. -->

    <permission name="android.permission.BLUETOOTH_ADMIN" >
        <group gid="net_bt_admin" />
    </permission>

    <permission name="android.permission.BLUETOOTH" >
        <group gid="net_bt" />
    </permission>

    <permission name="android.permission.BLUETOOTH_STACK" >
        <group gid="bluetooth" />
        <group gid="wakelock" />
        <group gid="uhid" />
    </permission>

    <permission name="android.permission.NET_TUNNELING" >
        <group gid="vpn" />
    </permission>

    <permission name="android.permission.INTERNET" >
        <group gid="inet" />
    </permission>

    <permission name="android.permission.READ_LOGS" >
        <group gid="log" />
    </permission>

    <permission name="android.permission.MANAGE_EXTERNAL_STORAGE" >
        <group gid="external_storage" />
    </permission>

    <permission name="android.permission.ACCESS_MTP" >
        <group gid="mtp" />
    </permission>

    <permission name="android.permission.NET_ADMIN" >
        <group gid="net_admin" />
    </permission>

    <permission name="android.permission.MAINLINE_NETWORK_STACK" >
        <group gid="net_admin" />
        <group gid="net_raw" />
    </permission>

    <!-- The group that /cache belongs to, linked to the permission
         set on the applications that can access /cache -->
    <permission name="android.permission.ACCESS_CACHE_FILESYSTEM" >
        <group gid="cache" />
    </permission>

    <!-- RW permissions to any system resources owned by group 'diag'.
         This is for carrier and manufacture diagnostics tools that must be
         installable from the framework. Be careful. -->
    <permission name="android.permission.DIAGNOSTIC" >
        <group gid="input" />
        <group gid="diag" />
    </permission>

    <!-- Group that can read detailed network usage statistics -->
    <permission name="android.permission.READ_NETWORK_USAGE_HISTORY">
        <group gid="net_bw_stats" />
    </permission>

    <!-- Group that can modify how network statistics are accounted -->
    <permission name="android.permission.UPDATE_DEVICE_STATS">
        <group gid="net_bw_acct" />
    </permission>

    <permission name="android.permission.LOOP_RADIO" >
        <group gid="loop_radio" />
    </permission>

    <!-- Hotword training apps sometimes need a GID to talk with low-level
         hardware; give them audio for now until full HAL support is added. -->
    <permission name="android.permission.MANAGE_VOICE_KEYPHRASES">
        <group gid="audio" />
    </permission>

    <permission name="android.permission.ACCESS_BROADCAST_RADIO" >
        <!-- /dev/fm is gid media, not audio -->
        <group gid="media" />
    </permission>

    <permission name="android.permission.USE_RESERVED_DISK">
        <group gid="reserved_disk" />
    </permission>

    <!-- These are permissions that were mapped to gids but we need
         to keep them here until an upgrade from L to the current
         version is to be supported. These permissions are built-in
         and in L were not stored in packages.xml as a result if they
         are not defined here while parsing packages.xml we would
         ignore these permissions being granted to apps and not
         propagate the granted state. From N we are storing the
         built-in permissions in packages.xml as the saved storage
         is negligible (one tag with the permission) compared to
         the fragility as one can remove a built-in permission which
         no longer needs to be mapped to gids and break grant propagation. -->
    <permission name="android.permission.READ_EXTERNAL_STORAGE" />
    <permission name="android.permission.WRITE_EXTERNAL_STORAGE" />

    <!-- ================================================================== -->
    <!-- ================================================================== -->
    <!-- ================================================================== -->

    <!-- The following tags are assigning high-level permissions to specific
         user IDs.  These are used to allow specific core system users to
         perform the given operations with the higher-level framework.  For
         example, we give a wide variety of permissions to the shell user
         since that is the user the adb shell runs under and developers and
         others should have a fairly open environment in which to
         interact with the system. -->

    <assign-permission name="android.permission.MODIFY_AUDIO_SETTINGS" uid="media" />
    <assign-permission name="android.permission.ACCESS_SURFACE_FLINGER" uid="media" />
    <assign-permission name="android.permission.WAKE_LOCK" uid="media" />
    <assign-permission name="android.permission.UPDATE_DEVICE_STATS" uid="media" />
    <assign-permission name="android.permission.UPDATE_APP_OPS_STATS" uid="media" />
    <assign-permission name="android.permission.GET_PROCESS_STATE_AND_OOM_SCORE" uid="media" />
    <assign-permission name="android.permission.INTERNET" uid="media" />

    <assign-permission name="android.permission.INTERNET" uid="shell" />

    <assign-permission name="android.permission.MODIFY_AUDIO_SETTINGS" uid="audioserver" />
    <assign-permission name="android.permission.ACCESS_SURFACE_FLINGER" uid="audioserver" />
    <assign-permission name="android.permission.WAKE_LOCK" uid="audioserver" />
    <assign-permission name="android.permission.UPDATE_DEVICE_STATS" uid="audioserver" />
    <assign-permission name="android.permission.UPDATE_APP_OPS_STATS" uid="audioserver" />
    <assign-permission name="android.permission.PACKAGE_USAGE_STATS" uid="audioserver" />

    <assign-permission name="android.permission.MODIFY_AUDIO_SETTINGS" uid="cameraserver" />
    <assign-permission name="android.permission.ACCESS_SURFACE_FLINGER" uid="cameraserver" />
    <assign-permission name="android.permission.WAKE_LOCK" uid="cameraserver" />
    <assign-permission name="android.permission.UPDATE_DEVICE_STATS" uid="cameraserver" />
    <assign-permission name="android.permission.UPDATE_APP_OPS_STATS" uid="cameraserver" />
    <assign-permission name="android.permission.GET_PROCESS_STATE_AND_OOM_SCORE" uid="cameraserver" />
    <assign-permission name="android.permission.PACKAGE_USAGE_STATS" uid="cameraserver" />
    <assign-permission name="android.permission.WATCH_APPOPS" uid="cameraserver" />
    <assign-permission name="android.permission.MANAGE_APP_OPS_MODES" uid="cameraserver" />

    <assign-permission name="android.permission.ACCESS_SURFACE_FLINGER" uid="graphics" />

    <assign-permission name="android.permission.DUMP" uid="incidentd" />
    <assign-permission name="android.permission.PACKAGE_USAGE_STATS" uid="incidentd" />
    <assign-permission name="android.permission.INTERACT_ACROSS_USERS" uid="incidentd" />
    <assign-permission name="android.permission.REQUEST_INCIDENT_REPORT_APPROVAL" uid="incidentd" />
    <assign-permission name="android.permission.PEEK_DROPBOX_DATA" uid="incidentd" />

    <assign-permission name="android.permission.ACCESS_LOWPAN_STATE" uid="lowpan" />
    <assign-permission name="android.permission.MANAGE_LOWPAN_INTERFACES" uid="lowpan" />

    <assign-permission name="android.permission.DUMP" uid="statsd" />
    <assign-permission name="android.permission.PACKAGE_USAGE_STATS" uid="statsd" />
    <assign-permission name="android.permission.STATSCOMPANION" uid="statsd" />
    <assign-permission name="android.permission.UPDATE_APP_OPS_STATS" uid="statsd" />

    <assign-permission name="android.permission.REGISTER_STATS_PULL_ATOM" uid="gpu_service" />

    <split-permission name="android.permission.ACCESS_FINE_LOCATION">
        <new-permission name="android.permission.ACCESS_COARSE_LOCATION" />
    </split-permission>
    <split-permission name="android.permission.WRITE_EXTERNAL_STORAGE">
        <new-permission name="android.permission.READ_EXTERNAL_STORAGE" />
    </split-permission>
    <split-permission name="android.permission.READ_PRIVILEGED_PHONE_STATE">
        <new-permission name="android.permission.READ_PHONE_STATE" />
    </split-permission>
    <split-permission name="android.permission.READ_CONTACTS"
                      targetSdk="16">
        <new-permission name="android.permission.READ_CALL_LOG" />
    </split-permission>
    <split-permission name="android.permission.WRITE_CONTACTS"
                      targetSdk="16">
        <new-permission name="android.permission.WRITE_CALL_LOG" />
    </split-permission>
    <split-permission name="android.permission.ACCESS_FINE_LOCATION"
                      targetSdk="29">
        <new-permission name="android.permission.ACCESS_BACKGROUND_LOCATION" />
    </split-permission>
    <split-permission name="android.permission.ACCESS_COARSE_LOCATION"
                      targetSdk="29">
        <new-permission name="android.permission.ACCESS_BACKGROUND_LOCATION" />
    </split-permission>
    <split-permission name="android.permission.READ_EXTERNAL_STORAGE"
                      targetSdk="29">
        <new-permission name="android.permission.ACCESS_MEDIA_LOCATION" />
    </split-permission>

    <!-- This is a list of all the libraries available for application
         code to link against. -->

    <library name="android.test.base"
            file="/system/framework/android.test.base.jar" />
    <library name="android.test.mock"
            file="/system/framework/android.test.mock.jar"
            dependency="android.test.base" />
    <library name="android.test.runner"
            file="/system/framework/android.test.runner.jar"
            dependency="android.test.base:android.test.mock" />

    <!-- In BOOT_JARS historically, and now added to legacy applications. -->
    <library name="android.hidl.base-V1.0-java"
            file="/system/framework/android.hidl.base-V1.0-java.jar" />
    <library name="android.hidl.manager-V1.0-java"
            file="/system/framework/android.hidl.manager-V1.0-java.jar"
            dependency="android.hidl.base-V1.0-java" />

    <!-- These are the standard packages that are white-listed to always have internet
         access while in power save mode, even if they aren't in the foreground. -->
    <allow-in-power-save package="com.android.providers.downloads" />

    <!-- These are the standard packages that are white-listed to always have internet
         access while in data mode, even if they aren't in the foreground. -->
    <allow-in-data-usage-save package="com.android.providers.downloads" />

    <!-- This is a core platform component that needs to freely run in the background -->
    <allow-in-power-save package="com.android.cellbroadcastreceiver.module" />
    <allow-in-power-save package="com.android.cellbroadcastreceiver" />
    <allow-in-power-save package="com.android.shell" />
    <allow-in-power-save package="com.android.deskclock" />
    <allow-in-power-save package="com.android.gallery3d" />

    <!-- Whitelist system providers -->
    <allow-in-power-save-except-idle package="com.android.providers.calendar" />
    <allow-in-power-save-except-idle package="com.android.providers.contacts" />

    <!-- The PAC proxy process must have network access, otherwise no app will
         be able to connect to the internet when such a proxy is in use, since
         all outgoing connections originate from this app. -->
    <allow-in-power-save-except-idle package="com.android.proxyhandler" />

    <!-- These are the packages that are white-listed to be able to run as system user -->
    <system-user-whitelisted-app package="com.android.settings" />

    <!-- These are the packages that shouldn't run as system user -->
    <system-user-blacklisted-app package="com.android.wallpaper.livepicker" />
</permissions>
    <permission name="android.permission.BLUETOOTH_ADMIN" >
        <group gid="net_bt_admin" />
    </permission>

以上的permission标签建立linux的gid和Android权限之间的联系

    <assign-permission name="android.permission.MODIFY_AUDIO_SETTINGS" uid="media" />

assign-permission标签向uid添加Android权限

    <library name="android.test.mock"
            file="/system/framework/android.test.mock.jar"
            dependency="android.test.base" />

library用于指定系统库,当应用程序运行时,系统会自动为这些进程加载这些库。

  • allow-in-power-save:这个标签用于指定在省电模式下允许访问互联网的应用程序。例如,com.android.providers.downloads是一个被允许在省电模式下访问互联网的应用程序。

  • allow-in-data-usage-save:这个标签用于指定在数据模式下允许访问互联网的应用程序。例如,com.android.providers.downloads是一个被允许在数据模式下访问互联网的应用程序。

  • allow-in-power-save-except-idle:这个标签用于指定在省电模式下允许访问互联网的应用程序,但不包括空闲模式。例如,com.android.providers.calendar是一个被允许在省电模式下访问互联网,但不包括空闲模式的应用程序。

  • system-user-whitelisted-app:这个标签用于指定被允许以系统用户身份运行的应用程序。例如,com.android.settings是一个被允许以系统用户身份运行的应用程序。

  • system-user-blacklisted-app:这个标签用于指定不允许以系统用户身份运行的应用程序。例如,com.android.wallpaper.livepicker是一个不允许以系统用户身份运行的应用程序。

2.2 构造函数分析之扫描Package

PMS构造函数第一阶段的工作是扫描解析XML文件,第二阶段就是扫描系统中的apk了。
第二阶段首先会进行一些初始化操作,包括创建线程、处理程序和处理器,添加到看门狗机制中,以及添加内置共享库到包管理服务中。这些操作为后续的包管理服务提供了必要的基础设置和准备工作。还会添加共享库之间的依赖关系信息、解析和读取包管理器的设置文件、清理不存在代码路径的孤立包。

之后会进入核心阶段,扫描Package:

            final int systemParseFlags = mDefParseFlags | PackageParser.PARSE_IS_SYSTEM_DIR;
            final int systemScanFlags = scanFlags | SCAN_AS_SYSTEM;

            PackageParser2 packageParser = new PackageParser2(mSeparateProcesses, mOnlyCore,
                    mMetrics, mCacheDir, mPackageParserCallback);

            ExecutorService executorService = ParallelPackageParser.makeExecutorService();
            // Prepare apex package info before scanning APKs, these information are needed when
            // scanning apk in apex.
            mApexManager.scanApexPackagesTraced(packageParser, executorService);
            // Collect vendor/product/system_ext overlay packages. (Do this before scanning
            // any apps.)
            // For security and version matching reason, only consider overlay packages if they
            // reside in the right directory.
            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);
            }

            scanDirTracedLI(frameworkDir, systemParseFlags,
                    systemScanFlags | SCAN_NO_DEX | SCAN_AS_PRIVILEGED, 0,
                    packageParser, executorService);
            if (!mPackages.containsKey("android")) {
                throw new IllegalStateException(
                        "Failed to load frameworks package; check log for warnings");
            }
            for (int i = 0, size = mDirsToScanAsSystem.size(); i < size; i++) {
                final ScanPartition partition = mDirsToScanAsSystem.get(i);
                if (partition.getPrivAppFolder() != null) {
                    scanDirTracedLI(partition.getPrivAppFolder(), systemParseFlags,
                            systemScanFlags | SCAN_AS_PRIVILEGED | partition.scanFlag, 0,
                            packageParser, executorService);
                }
                scanDirTracedLI(partition.getAppFolder(), systemParseFlags,
                        systemScanFlags | partition.scanFlag, 0,
                        packageParser, executorService);
            }

            preinstallThirdPartyAPK(packageParser,executorService,scanFlags);

代码创建了一个PackageParser2对象packageParser,用于解析APK文件。
代码创建了一个ExecutorService对象executorService,用于并行处理解析APK文件的任务。
-代码调用mApexManager.scanApexPackagesTraced()方法,对APEX包进行扫描和处理。这个操作在扫描APK文件之前进行,因为扫描APEX包时需要相关的信息。
通过一个循环遍历mDirsToScanAsSystem列表,对系统目录中的覆盖包进行扫描和处理。只有当覆盖包所在的目录存在时,才会进行扫描。
代码调用scanDirTracedLI()方法,对指定目录进行扫描和处理。这个方法会传递解析和扫描的标志、packageParser对象和executorService对象。
代码继续调用scanDirTracedLI()方法,对frameworkDir目录进行扫描和处理。这个目录通常包含Android框架的相关文件。
代码检查是否成功加载了名为"android"的框架包,如果没有加载成功,则抛出IllegalStateException异常。
最后,代码通过一个循环遍历mDirsToScanAsSystem列表,对系统目录中的特权应用程序和普通应用程序进行扫描和处理。
最后的方法根据名字来看应该是预安装第三方apk

scanDirTracedLI()方法用于对指定目录进行扫描和处理,方法中主要是调用了scanDirLI方法:

private void scanDirLI(File scanDir, int parseFlags, int scanFlags, long currentTime,
        PackageParser2 packageParser, ExecutorService executorService) {
    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));
    }

    ArrayList<String> list = new ArrayList<String>();
    boolean isPrebundled = (parseFlags & PackageParser.PARSE_IS_PREBUNDLED_DIR) != 0;
    if (isPrebundled) {
        synchronized (mPackages) {
            mSettings.readPrebundledPackagesLPr();
        }
    }

    if (scanDir.getAbsolutePath().contains(BUNDLED_UNINSTALL_GONE_DIR)) {
        if (!readDeleteFile(list)) {
            Log.e(TAG, "read data failed");
            return;
        }
    }

    ParallelPackageParser parallelPackageParser =
            new ParallelPackageParser(packageParser, executorService);

    // Submit files for parsing in parallel
    int fileCount = 0;
    for (File file : files) {
        final boolean isPackage = (isApkFile(file) || file.isDirectory())
                && !PackageInstallerService.isStageName(file.getName());
        if (!isPackage) {
            // Ignore entries which are not packages
            continue;
        }
        if (file.getAbsolutePath().contains(BUNDLED_UNINSTALL_GONE_DIR)) {
            if (list != null && list.size() > 0) {
                final boolean isdeleteApk = isDeleteApk(file,parseFlags,list);
                if (isdeleteApk) {
                    // Ignore deleted bundled apps
                    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.parsedPackage.isStaticSharedLibrary()) {
                renameStaticSharedLibraryPackage(parseResult.parsedPackage);
            }
            try {
                addForInitLI(parseResult.parsedPackage, parseFlags, scanFlags,
                        currentTime, null);
                if (isPrebundled) {
                    final PackageParser.Package pkg;
                    try {
                        pkg = new PackageParser().parsePackage(parseResult.scanFile, parseFlags);
                    } catch (PackageParserException e) {
                        throw PackageManagerException.from(e);
                    }
                    synchronized (mPackages) {
                        mSettings.markPrebundledPackageInstalledLPr(pkg.packageName);
                    }
                }
            } catch (PackageManagerException e) {
                errorCode = e.error;
                Slog.w(TAG, "Failed to scan " + parseResult.scanFile + ": " + e.getMessage());
            }
        } else if (throwable instanceof PackageParserException) {
            PackageParserException e = (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);
        }

        if ((scanFlags & SCAN_AS_APK_IN_APEX) != 0 && errorCode != INSTALL_SUCCEEDED) {
            mApexManager.reportErrorWithApkInApex(scanDir.getAbsolutePath());
        }

        // 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);
        }
    }

    if (isPrebundled) {
        synchronized (mPackages) {
            mSettings.writePrebundledPackagesLPr();
        }
    }
}

方法中创建了一个ParallelPackageParser对象parallelPackageParser,用于并行解析包。
parallelPackageParser.submit(file, parseFlags); 这句代码是解析包的关键
这里解析完成后,会对结果挨个进行处理,处理时调用的主要函数就是 addForInitLI

ParallelPackageParser:
PMS会对多个目录下的多个apk文件进行解析,工作量巨大,在Android9之后引入ParallelPackageParser类来并发执行解析,ParallelPackageParser使用线程池和队列执行程序的解析任务
frameworks/base/services/core/java/com/android/server/pm/ParallelPackageParser.java

class ParallelPackageParser {
    //保存请求结果的队列,会阻塞线程
    private final BlockingQueue<ParseResult> mQueue = new ArrayBlockingQueue<>(QUEUE_CAPACITY);
    //创建固定线程数的线程池
    static ExecutorService makeExecutorService() {
        return ConcurrentUtils.newFixedThreadPool(MAX_THREADS, "package-parsing-thread",
                Process.THREAD_PRIORITY_FOREGROUND);
    }
    
    private final PackageParser2 mPackageParser;

    private final ExecutorService mExecutorService;
    ParallelPackageParser(PackageParser2 packageParser, ExecutorService executorService) {
        mPackageParser = packageParser;
        mExecutorService = executorService;
    }
    public void submit(File scanFile, int parseFlags) {
        mExecutorService.submit(() -> {
            ParseResult pr = new ParseResult();
            Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "parallel parsePackage [" + scanFile + "]");
            try {
                pr.scanFile = scanFile;
                pr.parsedPackage = parsePackage(scanFile, parseFlags);
            } catch (Throwable e) {
                pr.throwable = e;
            } finally {
                Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
            }
            try {
                mQueue.put(pr);
            } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
                // Propagate result to callers of take().
                // This is helpful to prevent main thread from getting stuck waiting on
                // ParallelPackageParser to finish in case of interruption
                mInterruptedInThread = Thread.currentThread().getName();
            }
        });
    }
    @VisibleForTesting
    protected ParsedPackage parsePackage(File scanFile, int parseFlags)
            throws PackageParser.PackageParserException {
        return mPackageParser.parsePackage(scanFile, parseFlags, true);
    }
}
    }

submit最后调用到的是PackageParser2的parsePackage方法:
frameworks/base/services/core/java/com/android/server/pm/parsing/PackageParser2.java

    @AnyThread
    public ParsedPackage parsePackage(File packageFile, int flags, boolean useCaches)
            throws PackageParserException {
        if (useCaches && mCacher != null) {
            ParsedPackage parsed = mCacher.getCachedResult(packageFile, flags);
            if (parsed != null) {
                return parsed;
            }
        }

        long parseTime = LOG_PARSE_TIMINGS ? SystemClock.uptimeMillis() : 0;
        ParseInput input = mSharedResult.get().reset();
        ParseResult<ParsingPackage> result = parsingUtils.parsePackage(input, packageFile, flags);
        if (result.isError()) {
            throw new PackageParserException(result.getErrorCode(), result.getErrorMessage(),
                    result.getException());
        }

        ParsedPackage parsed = (ParsedPackage) result.getResult().hideAsParsed();

        long cacheTime = LOG_PARSE_TIMINGS ? SystemClock.uptimeMillis() : 0;
        if (mCacher != null) {
            mCacher.cacheResult(packageFile, flags, parsed);
        }
        if (LOG_PARSE_TIMINGS) {
            parseTime = cacheTime - parseTime;
            cacheTime = SystemClock.uptimeMillis() - cacheTime;
            if (parseTime + cacheTime > LOG_PARSE_TIMINGS_THRESHOLD_MS) {
                Slog.i(TAG, "Parse times for '" + packageFile + "': parse=" + parseTime
                        + "ms, update_cache=" + cacheTime + " ms");
            }
        }

        return parsed;
    }

调用parsingUtils.parsePackage
frameworks/base/core/java/android/content/pm/parsing/ParsingPackageUtils.java

    public ParseResult<ParsingPackage> parsePackage(ParseInput input, File packageFile,
            int flags)
            throws PackageParserException {
        if (packageFile.isDirectory()) {
            return parseClusterPackage(input, packageFile, flags);
        } else {
            return parseMonolithicPackage(input, packageFile, flags);
        }
    }
    
    private ParseResult<ParsingPackage> parseMonolithicPackage(ParseInput input, File apkFile,
            int flags) throws PackageParserException {
        ParseResult<PackageParser.PackageLite> liteResult =
                ApkLiteParseUtils.parseMonolithicPackageLite(input, apkFile, flags);
        if (liteResult.isError()) {
            return input.error(liteResult);
        }

        final PackageParser.PackageLite lite = liteResult.getResult();
        if (mOnlyCoreApps && !lite.coreApp) {
            return input.error(INSTALL_PARSE_FAILED_ONLY_COREAPP_ALLOWED,
                    "Not a coreApp: " + apkFile);
        }

        final SplitAssetLoader assetLoader = new DefaultSplitAssetLoader(lite, flags);
        try {
            ParseResult<ParsingPackage> result = parseBaseApk(input,
                    apkFile,
                    apkFile.getCanonicalPath(),
                    assetLoader.getBaseAssetManager(), flags);
            if (result.isError()) {
                return input.error(result);
            }

            return input.success(result.getResult()
                    .setUse32BitAbi(lite.use32bitAbi));
        } catch (IOException e) {
            return input.error(INSTALL_PARSE_FAILED_UNEXPECTED_EXCEPTION,
                    "Failed to get path: " + apkFile, e);
        } finally {
            IoUtils.closeQuietly(assetLoader);
        }
    }

根据是文件夹还是apk,执行不同的方法
parseMonolithicPackage执行parseBaseApk解析apk

    private ParseResult<ParsingPackage> parseBaseApk(ParseInput input, File apkFile,
            String codePath, AssetManager assets, int flags) {
        final String apkPath = apkFile.getAbsolutePath();

        String volumeUuid = null;
        if (apkPath.startsWith(PackageParser.MNT_EXPAND)) {
            final int end = apkPath.indexOf('/', PackageParser.MNT_EXPAND.length());
            volumeUuid = apkPath.substring(PackageParser.MNT_EXPAND.length(), end);
        }

        if (PackageParser.DEBUG_JAR) Slog.d(TAG, "Scanning base APK: " + apkPath);

        final int cookie = assets.findCookieForPath(apkPath);
        if (cookie == 0) {
            return input.error(INSTALL_PARSE_FAILED_BAD_MANIFEST,
                    "Failed adding asset path: " + apkPath);
        }
        //ANDROID_MANIFEST_FILENAME就是Androidmanifest.xml
        try (XmlResourceParser parser = assets.openXmlResourceParser(cookie,
                PackageParser.ANDROID_MANIFEST_FILENAME)) {
            final Resources res = new Resources(assets, mDisplayMetrics, null);

            ParseResult<ParsingPackage> result = parseBaseApk(input, apkPath, codePath, res,
                    parser, flags);
            if (result.isError()) {
                return input.error(result.getErrorCode(),
                        apkPath + " (at " + parser.getPositionDescription() + "): "
                                + result.getErrorMessage());
            }

            final ParsingPackage pkg = result.getResult();
            if (assets.containsAllocatedTable()) {
                final ParseResult<?> deferResult = input.deferError(
                        "Targeting R+ (version " + Build.VERSION_CODES.R + " and above) requires"
                                + " the resources.arsc of installed APKs to be stored uncompressed"
                                + " and aligned on a 4-byte boundary",
                        DeferredError.RESOURCES_ARSC_COMPRESSED);
                if (deferResult.isError()) {
                    return input.error(INSTALL_PARSE_FAILED_RESOURCES_ARSC_COMPRESSED,
                            deferResult.getErrorMessage());
                }
            }

            ApkAssets apkAssets = assets.getApkAssets()[0];
            if (apkAssets.definesOverlayable()) {
                SparseArray<String> packageNames = assets.getAssignedPackageIdentifiers();
                int size = packageNames.size();
                for (int index = 0; index < size; index++) {
                    String packageName = packageNames.get(index);
                    Map<String, String> overlayableToActor = assets.getOverlayableMap(packageName);
                    if (overlayableToActor != null && !overlayableToActor.isEmpty()) {
                        for (String overlayable : overlayableToActor.keySet()) {
                            pkg.addOverlayable(overlayable, overlayableToActor.get(overlayable));
                        }
                    }
                }
            }

            pkg.setVolumeUuid(volumeUuid);

            if ((flags & PackageParser.PARSE_COLLECT_CERTIFICATES) != 0) {
                pkg.setSigningDetails(getSigningDetails(pkg, false));
            } else {
                pkg.setSigningDetails(SigningDetails.UNKNOWN);
            }

            return input.success(pkg);
        } catch (Exception e) {
            return input.error(INSTALL_PARSE_FAILED_UNEXPECTED_EXCEPTION,
                    "Failed to read manifest from " + apkPath, e);
        }
    }

XmlResourceParser parser = assets.openXmlResourceParser(cookie,
PackageParser.ANDROID_MANIFEST_FILENAME)这里就是解析Androidmanifest.xml
之后调用了另一个六参的重载方法

    private ParseResult<ParsingPackage> parseBaseApk(ParseInput input, String apkPath,
            String codePath, Resources res, XmlResourceParser parser, int flags)
            throws XmlPullParserException, IOException, PackageParserException {
        final String splitName;
        final String pkgName;

        ParseResult<Pair<String, String>> packageSplitResult =
                ApkLiteParseUtils.parsePackageSplitNames(input, parser, parser);
        if (packageSplitResult.isError()) {
            return input.error(packageSplitResult);
        }

        Pair<String, String> packageSplit = packageSplitResult.getResult();
        pkgName = packageSplit.first;
        splitName = packageSplit.second;

        if (!TextUtils.isEmpty(splitName)) {
            return input.error(
                    PackageManager.INSTALL_PARSE_FAILED_BAD_PACKAGE_NAME,
                    "Expected base APK, but found split " + splitName
            );
        }

        final TypedArray manifestArray = res.obtainAttributes(parser, R.styleable.AndroidManifest);
        try {
            final boolean isCoreApp =
                    parser.getAttributeBooleanValue(null, "coreApp", false);
            final ParsingPackage pkg = mCallback.startParsingPackage(
                    pkgName, apkPath, codePath, manifestArray, isCoreApp);
            final ParseResult<ParsingPackage> result =
                    parseBaseApkTags(input, pkg, manifestArray, res, parser, flags);
            if (result.isError()) {
                return result;
            }

            return input.success(pkg);
        } finally {
            manifestArray.recycle();
        }
    }

调用parseBaseApkTags

    private ParseResult<ParsingPackage> parseBaseApkTags(ParseInput input, ParsingPackage pkg,
            TypedArray sa, Resources res, XmlResourceParser parser, int flags)
            throws XmlPullParserException, IOException {
        ParseResult<ParsingPackage> sharedUserResult = parseSharedUser(input, pkg, sa);
        if (sharedUserResult.isError()) {
            return sharedUserResult;
        }

        pkg.setInstallLocation(anInteger(PackageParser.PARSE_DEFAULT_INSTALL_LOCATION,
                R.styleable.AndroidManifest_installLocation, sa))
                .setTargetSandboxVersion(anInteger(PackageParser.PARSE_DEFAULT_TARGET_SANDBOX,
                        R.styleable.AndroidManifest_targetSandboxVersion, sa))
                /* Set the global "on SD card" flag */
                .setExternalStorage((flags & PackageParser.PARSE_EXTERNAL_STORAGE) != 0);

        boolean foundApp = false;
        final int depth = parser.getDepth();
        int type;
        while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
                && (type != XmlPullParser.END_TAG
                || parser.getDepth() > depth)) {
            if (type != XmlPullParser.START_TAG) {
                continue;
            }

            String tagName = parser.getName();
            final ParseResult result;

            // TODO(b/135203078): Convert to instance methods to share variables
            // <application> has special logic, so it's handled outside the general method
            if (PackageParser.TAG_APPLICATION.equals(tagName)) {
                if (foundApp) {
                    if (PackageParser.RIGID_PARSER) {
                        result = input.error("<manifest> has more than one <application>");
                    } else {
                        Slog.w(TAG, "<manifest> has more than one <application>");
                        result = input.success(null);
                    }
                } else {
                    foundApp = true;
                    result = parseBaseApplication(input, pkg, res, parser, flags);
                }
            } else {
                result = parseBaseApkTag(tagName, input, pkg, res, parser, flags);
            }

            if (result.isError()) {
                return input.error(result);
            }
        }

        if (!foundApp && ArrayUtils.size(pkg.getInstrumentations()) == 0) {
            ParseResult<?> deferResult = input.deferError(
                    "<manifest> does not contain an <application> or <instrumentation>",
                    DeferredError.MISSING_APP_TAG);
            if (deferResult.isError()) {
                return input.error(deferResult);
            }
        }

        if (!ParsedAttribution.isCombinationValid(pkg.getAttributions())) {
            return input.error(
                    INSTALL_PARSE_FAILED_BAD_MANIFEST,
                    "Combination <feature> tags are not valid"
            );
        }

        convertNewPermissions(pkg);

        convertSplitPermissions(pkg);

        // At this point we can check if an application is not supporting densities and hence
        // cannot be windowed / resized. Note that an SDK version of 0 is common for
        // pre-Doughnut applications.
        if (pkg.getTargetSdkVersion() < DONUT
                || (!pkg.isSupportsSmallScreens()
                && !pkg.isSupportsNormalScreens()
                && !pkg.isSupportsLargeScreens()
                && !pkg.isSupportsExtraLargeScreens()
                && !pkg.isResizeable()
                && !pkg.isAnyDensity())) {
            adjustPackageToBeUnresizeableAndUnpipable(pkg);
        }

        return input.success(pkg);
    }

使用循环遍历解析器中的标签,直到遇到文档结束标签或者深度小于初始深度的结束标签。在循环中,代码判断当前标签的类型,如果不是开始标签,则继续下一次循环。
调用parseBaseApplication:
parseBaseApplication方法太长,主要是在解析各个标签:
在这里插入图片描述
在这个方法或许可以来强制修改apk的某些属性
自此apk解析完毕,回到PMS继续看addForInitLI方法
frameworks/base/services/core/java/com/android/server/pm/PackageManagerService.java

private AndroidPackage addForInitLI(ParsedPackage parsedPackage,
        @ParseFlags int parseFlags, @ScanFlags int scanFlags, long currentTime,
        @Nullable UserHandle user)
                throws PackageManagerException {

    ...

    final ScanResult scanResult = scanPackageNewLI(parsedPackage, parseFlags, scanFlags
            | SCAN_UPDATE_SIGNATURE, currentTime, user, null);
    if (scanResult.success) {
        synchronized (mLock) {
            boolean appIdCreated = false;
            try {
                final String pkgName = scanResult.pkgSetting.name;
                final Map<String, ReconciledPackage> reconcileResult = reconcilePackagesLocked(
                        new ReconcileRequest(
                                Collections.singletonMap(pkgName, scanResult),
                                mSharedLibraries,
                                mPackages,
                                Collections.singletonMap(
                                        pkgName, getSettingsVersionForPackage(parsedPackage)),
                                Collections.singletonMap(pkgName,
                                        getSharedLibLatestVersionSetting(scanResult))),
                        mSettings.mKeySetManagerService);
                appIdCreated = optimisticallyRegisterAppId(scanResult);
                commitReconciledScanResultLocked(
                        reconcileResult.get(pkgName), mUserManager.getUserIds());
            } catch (PackageManagerException e) {
                if (appIdCreated) {
                    cleanUpAppIdCreation(scanResult);
                }
                throw e;
            }
        }
    }

    if (shouldHideSystemApp) {
        synchronized (mLock) {
            mSettings.disableSystemPackageLPw(parsedPackage.getPackageName(), true);
        }
    }
    return scanResult.pkgSetting.pkg;
}

调用scanPackageNewLI获取scanResult对象
调用commitReconciledScanResultLocked提交结果,commitReconciledScanResultLocked中调用commitPackageSettings

private void commitPackageSettings(AndroidPackage pkg,
            @Nullable AndroidPackage oldPkg, PackageSetting pkgSetting,
        final @ScanFlags int scanFlags, boolean chatty, ReconciledPackage reconciledPkg) {
    final String pkgName = pkg.getPackageName();
    // 判断是不是自定义的ResolverComponentName,这个ResolverComponentName后面再分析
    if (mCustomResolverComponentName != null &&
            mCustomResolverComponentName.getPackageName().equals(pkg.getPackageName())) {
        setUpCustomResolverActivity(pkg, pkgSetting);
    }

    if (pkg.getPackageName().equals("android")) {
        synchronized (mLock) {
            // Set up information for our fall-back user intent resolution activity.
            mPlatformPackage = pkg;

            // The instance stored in PackageManagerService is special cased to be non-user
            // specific, so initialize all the needed fields here.
            mAndroidApplication = pkg.toAppInfoWithoutState();
            mAndroidApplication.flags = PackageInfoUtils.appInfoFlags(pkg, pkgSetting);
            mAndroidApplication.privateFlags =
                    PackageInfoUtils.appInfoPrivateFlags(pkg, pkgSetting);
            mAndroidApplication.initForUser(UserHandle.USER_SYSTEM);

            if (!mResolverReplaced) {
                mResolveActivity.applicationInfo = mAndroidApplication;
                mResolveActivity.name = ResolverActivity.class.getName();
                mResolveActivity.packageName = mAndroidApplication.packageName;
                mResolveActivity.processName = "system:ui";
                mResolveActivity.launchMode = ActivityInfo.LAUNCH_MULTIPLE;
                mResolveActivity.documentLaunchMode = ActivityInfo.DOCUMENT_LAUNCH_NEVER;
                mResolveActivity.flags = ActivityInfo.FLAG_EXCLUDE_FROM_RECENTS;
                mResolveActivity.theme = R.style.Theme_Material_Dialog_Alert;
                mResolveActivity.exported = true;
                mResolveActivity.enabled = true;
                mResolveActivity.resizeMode = ActivityInfo.RESIZE_MODE_RESIZEABLE;
                mResolveActivity.configChanges = ActivityInfo.CONFIG_SCREEN_SIZE
                        | ActivityInfo.CONFIG_SMALLEST_SCREEN_SIZE
                        | ActivityInfo.CONFIG_SCREEN_LAYOUT
                        | ActivityInfo.CONFIG_ORIENTATION
                        | ActivityInfo.CONFIG_KEYBOARD
                        | ActivityInfo.CONFIG_KEYBOARD_HIDDEN;
                mResolveInfo.activityInfo = mResolveActivity;
                mResolveInfo.priority = 0;
                mResolveInfo.preferredOrder = 0;
                mResolveInfo.match = 0;
                mResolveComponentName = new ComponentName(
                        mAndroidApplication.packageName, mResolveActivity.name);
            }
        }
    }

    ...

    // writer
    Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "updateSettings");

    synchronized (mLock) {
        // We don't expect installation to fail beyond this point

        // 更新mSettings中相关包的数据
        mSettings.insertPackageSettingLPw(pkgSetting, pkg);
        // 存储包信息
        mPackages.put(pkg.getPackageName(), pkg);
        if ((scanFlags & SCAN_AS_APK_IN_APEX) != 0) {
            mApexManager.registerApkInApex(pkg);
        }

        // 把KeySets添加到KeySetManagerService
        KeySetManagerService ksms = mSettings.mKeySetManagerService;
        ksms.addScannedPackageLPw(pkg);

        // 向mComponentResolver注册
        mComponentResolver.addAllComponents(pkg, chatty);
        final boolean isReplace =
                reconciledPkg.prepareResult != null && reconciledPkg.prepareResult.replace;
        // 向mAppsFilter注册
        mAppsFilter.addPackage(pkgSetting, isReplace);

        // 不允许临时应用程序定义新的权限组
        if ((scanFlags & SCAN_AS_INSTANT_APP) != 0) {
            Slog.w(TAG, "Permission groups from package " + pkg.getPackageName()
                    + " ignored: instant apps cannot define new permission groups.");
        } else {
            // 权限组相关处理
            mPermissionManager.addAllPermissionGroups(pkg, chatty);
        }

        // 不允许临时应用程序定义新的权限
        if ((scanFlags & SCAN_AS_INSTANT_APP) != 0) {
            Slog.w(TAG, "Permissions from package " + pkg.getPackageName()
                    + " ignored: instant apps cannot define new permissions.");
        } else {
            // 权限相关处理
            mPermissionManager.addAllPermissions(pkg, chatty);
        }

        int collectionSize = ArrayUtils.size(pkg.getInstrumentations());
        StringBuilder r = null;
        int i;
        for (i = 0; i < collectionSize; i++) {
            ParsedInstrumentation a = pkg.getInstrumentations().get(i);
            a.setPackageName(pkg.getPackageName());
            // 向mInstrumentation注册  
            //mInstrumentation 是用来存储 Android 应用中的 instrumentation 类的信息的映射
            mInstrumentation.put(a.getComponentName(), a);
            if (chatty) {
                if (r == null) {
                    r = new StringBuilder(256);
                } else {
                    r.append(' ');
                }
                r.append(a.getName());
            }
        }
        if (r != null) {
            if (DEBUG_PACKAGE_SCANNING) Log.d(TAG, "  Instrumentation: " + r);
        }

        if (!pkg.getProtectedBroadcasts().isEmpty()) {
            synchronized (mProtectedBroadcasts) {
                mProtectedBroadcasts.addAll(pkg.getProtectedBroadcasts());
            }
        }

        if (oldPkg != null) {
            // We need to call revokeRuntimePermissionsIfGroupChanged async as permission
            // revoke callbacks from this method might need to kill apps which need the
            // mPackages lock on a different thread. This would dead lock.
            //
            // Hence create a copy of all package names and pass it into
            // revokeRuntimePermissionsIfGroupChanged. Only for those permissions might get
            // revoked. If a new package is added before the async code runs the permission
            // won't be granted yet, hence new packages are no problem.
            final ArrayList<String> allPackageNames = new ArrayList<>(mPackages.keySet());

            AsyncTask.execute(() ->
                    mPermissionManager.revokeRuntimePermissionsIfGroupChanged(pkg, oldPkg,
                            allPackageNames));
        }
    }

    Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
}

把解析的结果存储到PMS和Settings的相关变量中

自此整个扫描过程结束
之后在构造方法中还会扫描非系统目录的apk

            if (!mOnlyCore) {
                EventLog.writeEvent(EventLogTags.BOOT_PROGRESS_PMS_DATA_SCAN_START,
                        SystemClock.uptimeMillis());
                scanDirTracedLI(sAppInstallDir, 0, scanFlags | SCAN_REQUIRE_KNOWN, 0,
                        packageParser, executorService);

            }

            packageParser.close();

3、APK Installation分析

apk安装有多种形式,发送广播、手动安装、adb命令等等,所有方式最后都会走到PMS来
下面是packageInstaller中实际执行安装的代码
frameworks/base/packages/PackageInstaller/src/com/android/packageinstaller/InstallInstalling.java

               PackageInstaller.SessionParams params = new PackageInstaller.SessionParams(
                        PackageInstaller.SessionParams.MODE_FULL_INSTALL);
                params.setInstallAsInstantApp(false);
                params.setReferrerUri(getIntent().getParcelableExtra(Intent.EXTRA_REFERRER));
                params.setOriginatingUri(getIntent()
                        .getParcelableExtra(Intent.EXTRA_ORIGINATING_URI));
                params.setOriginatingUid(getIntent().getIntExtra(Intent.EXTRA_ORIGINATING_UID,
                        UID_UNKNOWN));
                params.setInstallerPackageName(getIntent().getStringExtra(
                        Intent.EXTRA_INSTALLER_PACKAGE_NAME));
                params.setInstallReason(PackageManager.INSTALL_REASON_USER);

                File file = new File(mPackageURI.getPath());
                try {
                    PackageParser.PackageLite pkg = PackageParser.parsePackageLite(file, 0);
                    params.setAppPackageName(pkg.packageName);
                    params.setInstallLocation(pkg.installLocation);
                    params.setSize(
                            PackageHelper.calculateInstalledSize(pkg, false, params.abiOverride));
                } catch (PackageParser.PackageParserException e) {
                    Log.e(LOG_TAG, "Cannot parse package " + file + ". Assuming defaults.");
                    Log.e(LOG_TAG,
                            "Cannot calculate installed size " + file + ". Try only apk size.");
                    params.setSize(file.length());
                } catch (IOException e) {
                    Log.e(LOG_TAG,
                            "Cannot calculate installed size " + file + ". Try only apk size.");
                    params.setSize(file.length());
                }

                try {
                    mInstallId = InstallEventReceiver
                            .addObserver(this, EventResultPersister.GENERATE_NEW_ID,
                                    this::launchFinishBasedOnResult);
                } catch (EventResultPersister.OutOfIdsException e) {
                    launchFailure(PackageManager.INSTALL_FAILED_INTERNAL_ERROR, null);
                }

                try {
                    mSessionId = getPackageManager().getPackageInstaller().createSession(params);
                } catch (IOException e) {
                    launchFailure(PackageManager.INSTALL_FAILED_INTERNAL_ERROR, null);
                }
        @Override
        protected PackageInstaller.Session doInBackground(Void... params) {
            PackageInstaller.Session session;
            try {
                session = getPackageManager().getPackageInstaller().openSession(mSessionId);
            } catch (IOException e) {
                synchronized (this) {
                    isDone = true;
                    notifyAll();
                }
                return null;
            }

            session.setStagingProgress(0);

            try {
                File file = new File(mPackageURI.getPath());

                try (InputStream in = new FileInputStream(file)) {
                    long sizeBytes = file.length();
                    try (OutputStream out = session
                            .openWrite("PackageInstaller", 0, sizeBytes)) {
                        byte[] buffer = new byte[1024 * 1024];
                        while (true) {
                            int numRead = in.read(buffer);

                            if (numRead == -1) {
                                session.fsync(out);
                                break;
                            }

                            if (isCancelled()) {
                                session.close();
                                break;
                            }

                            out.write(buffer, 0, numRead);
                            if (sizeBytes > 0) {
                                float fraction = ((float) numRead / (float) sizeBytes);
                                session.addProgress(fraction);
                            }
                        }
                    }
                }

                return session;
            } catch (IOException | SecurityException e) {
                Log.e(LOG_TAG, "Could not write package", e);

                session.close();

                return null;
            } finally {
                synchronized (this) {
                    isDone = true;
                    notifyAll();
                }
            }
        }

安装器中主要的安装逻辑就是这个session createSession openSession session.commit
frameworks/base/core/java/android/content/pm/PackageInstaller.java

        public void commit(@NonNull IntentSender statusReceiver) {
            try {
                mSession.commit(statusReceiver, false);
            } catch (RemoteException e) {
                throw e.rethrowFromSystemServer();
            }
        }

commit调用mSession.commit

protected final IPackageInstallerSession mSession;

mSession是IPackageInstallerSession对象 是一个aidl接口
具体实现在frameworks/base/services/core/java/com/android/server/pm/PackageInstallerSession.java

    @Override
    public void commit(@NonNull IntentSender statusReceiver, boolean forTransfer) {
        if (hasParentSessionId()) {
            throw new IllegalStateException(
                    "Session " + sessionId + " is a child of multi-package session "
                            + mParentSessionId +  " and may not be committed directly.");
        }

        if (!markAsSealed(statusReceiver, forTransfer)) {
            return;
        }
        if (isMultiPackage()) {
            final SparseIntArray remainingSessions = mChildSessionIds.clone();
            final IntentSender childIntentSender =
                    new ChildStatusIntentReceiver(remainingSessions, statusReceiver)
                            .getIntentSender();
            boolean sealFailed = false;
            for (int i = mChildSessionIds.size() - 1; i >= 0; --i) {
                final int childSessionId = mChildSessionIds.keyAt(i);
                // seal all children, regardless if any of them fail; we'll throw/return
                // as appropriate once all children have been processed
                if (!mSessionProvider.getSession(childSessionId)
                        .markAsSealed(childIntentSender, forTransfer)) {
                    sealFailed = true;
                }
            }
            if (sealFailed) {
                return;
            }
        }

        dispatchStreamValidateAndCommit();
    }

通过一系列调用,最后在installNonStagedLocked方法调用PMS的installStage

    @GuardedBy("mLock")
    private void installNonStagedLocked(List<PackageInstallerSession> childSessions)
            throws PackageManagerException {
        final PackageManagerService.ActiveInstallSession installingSession =
                makeSessionActiveLocked();
        if (installingSession == null) {
            return;
        }
        if (isMultiPackage()) {
            List<PackageManagerService.ActiveInstallSession> installingChildSessions =
                    new ArrayList<>(childSessions.size());
            boolean success = true;
            PackageManagerException failure = null;
            for (int i = 0; i < childSessions.size(); ++i) {
                final PackageInstallerSession session = childSessions.get(i);
                try {
                    final PackageManagerService.ActiveInstallSession installingChildSession =
                            session.makeSessionActiveLocked();
                    if (installingChildSession != null) {
                        installingChildSessions.add(installingChildSession);
                    }
                } catch (PackageManagerException e) {
                    failure = e;
                    success = false;
                }
            }
            if (!success) {
                sendOnPackageInstalled(mContext, mRemoteStatusReceiver, sessionId,
                        isInstallerDeviceOwnerOrAffiliatedProfileOwnerLocked(), userId, null,
                        failure.error, failure.getLocalizedMessage(), null);
                return;
            }
            mPm.installStage(installingChildSessions);
        } else {
            mPm.installStage(installingSession);
        }
    }

frameworks/base/services/core/java/com/android/server/pm/PackageManagerService.java

    void installStage(ActiveInstallSession activeInstallSession) {
        if (DEBUG_INSTANT) {
            if ((activeInstallSession.getSessionParams().installFlags
                    & PackageManager.INSTALL_INSTANT_APP) != 0) {
                Slog.d(TAG, "Ephemeral install of " + activeInstallSession.getPackageName());
            }
        }
        final Message msg = mHandler.obtainMessage(INIT_COPY);
        final InstallParams params = new InstallParams(activeInstallSession);
        params.setTraceMethod("installStage").setTraceCookie(System.identityHashCode(params));
        msg.obj = params;

        Trace.asyncTraceBegin(TRACE_TAG_PACKAGE_MANAGER, "installStage",
                System.identityHashCode(msg.obj));
        Trace.asyncTraceBegin(TRACE_TAG_PACKAGE_MANAGER, "queueInstall",
                System.identityHashCode(msg.obj));

        mHandler.sendMessage(msg);
    }
    
    
            void doHandleMessage(Message msg) {
            switch (msg.what) {
                case INIT_COPY: {
                    //if(android.provider.Settings.Global.getInt(mContext.getContentResolver(), "allow_install", 1) != 1){
                    //    Toast.makeText(mContext, "No permission, please contact the administrator2", Toast.LENGTH_LONG).show();
                    //    return;
                    //}
                    HandlerParams params = (HandlerParams) msg.obj;
                    if (params != null) {
                        if (DEBUG_INSTALL) Slog.i(TAG, "init_copy: " + params);
                        Trace.asyncTraceEnd(TRACE_TAG_PACKAGE_MANAGER, "queueInstall",
                                System.identityHashCode(params));
                        Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "startCopy");
                        params.startCopy();
                        Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
                    }
                    break;
                }
              }
            }

最后在doHandleMessage的INIT_COPY里执行安装操作,调用了HandlerParams 的startCopy。HandlerParams是一个抽象内部类,这里安装的installStage实现是在内部类InstallParams

        final void startCopy() {
            if (DEBUG_INSTALL) Slog.i(TAG, "startCopy " + mUser + ": " + this);
            handleStartCopy();
            handleReturnCode();
        }

        abstract void handleStartCopy();
        abstract void handleReturnCode();

InstallParams中handleStartCopy的实现:

        public void handleStartCopy() {
            int ret = PackageManager.INSTALL_SUCCEEDED;

            // If we're already staged, we've firmly committed to an install location
            //根据安装的来源和位置设置安装标志位,以便在后续的安装过程中正确处理安装位置
            if (origin.staged) {
                if (origin.file != null) {
                    installFlags |= PackageManager.INSTALL_INTERNAL;
                } else {
                    throw new IllegalStateException("Invalid stage location");
                }
            }
            //获取要安装的包的最小信息,并在需要时尝试释放缓存空间以解决存储空间不足的问题
            final boolean onInt = (installFlags & PackageManager.INSTALL_INTERNAL) != 0;
            final boolean ephemeral = (installFlags & PackageManager.INSTALL_INSTANT_APP) != 0;
            PackageInfoLite pkgLite = null;
            //获取最小化的包信息。它接收应用的路径、安装标志位和ABI覆盖参数作为输入,
            //并返回一个PackageInfoLite对象,该对象包含了应用的基本信息,如包名、版本号等。
            //这个方法通常用于获取应用的元数据信息,以便后续进行安装操作。
            //该方法最后会调用到PackageHelper.resolveInstallLocation来确定推荐安装位置
            //此处主要是为了获取pkgLite的recommendedInstallLocation值,表示apk推荐安装路径
            pkgLite = PackageManagerServiceUtils.getMinimalPackageInfo(mContext,
                    origin.resolvedPath, installFlags, packageAbiOverride);

            if (DEBUG_INSTANT && ephemeral) {
                Slog.v(TAG, "pkgLite for install: " + pkgLite);
            }

            /*
             * If we have too little free space, try to free cache
             * before giving up.
             */
            if (!origin.staged && pkgLite.recommendedInstallLocation
                    == PackageHelper.RECOMMEND_FAILED_INSUFFICIENT_STORAGE) {
                // TODO: focus freeing disk space on the target device
                final StorageManager storage = StorageManager.from(mContext);
                final long lowThreshold = storage.getStorageLowBytes(
                        Environment.getDataDirectory());

                final long sizeBytes = PackageManagerServiceUtils.calculateInstalledSize(
                        origin.resolvedPath, packageAbiOverride);
                if (sizeBytes >= 0) {
                    try {
                        mInstaller.freeCache(null, sizeBytes + lowThreshold, 0, 0);
                        pkgLite = PackageManagerServiceUtils.getMinimalPackageInfo(mContext,
                                origin.resolvedPath, installFlags, packageAbiOverride);
                    } catch (InstallerException e) {
                        Slog.w(TAG, "Failed to free cache", e);
                    }
                }

                /*
                 * The cache free must have deleted the file we downloaded to install.
                 *
                 * TODO: fix the "freeCache" call to not delete the file we care about.
                 */
                if (pkgLite.recommendedInstallLocation
                        == PackageHelper.RECOMMEND_FAILED_INVALID_URI) {
                    pkgLite.recommendedInstallLocation
                            = PackageHelper.RECOMMEND_FAILED_INSUFFICIENT_STORAGE;
                }
            }
            //根据pkgLite对象的推荐安装位置属性来确定安装的结果,并根据安装位置策略和标志位进一步处理安装位置
            if (ret == PackageManager.INSTALL_SUCCEEDED) {
                int loc = pkgLite.recommendedInstallLocation;
                if (loc == PackageHelper.RECOMMEND_FAILED_INVALID_LOCATION) {
                    ret = PackageManager.INSTALL_FAILED_INVALID_INSTALL_LOCATION;
                } else if (loc == PackageHelper.RECOMMEND_FAILED_ALREADY_EXISTS) {
                    ret = PackageManager.INSTALL_FAILED_ALREADY_EXISTS;
                } else if (loc == PackageHelper.RECOMMEND_FAILED_INSUFFICIENT_STORAGE) {
                    ret = PackageManager.INSTALL_FAILED_INSUFFICIENT_STORAGE;
                } else if (loc == PackageHelper.RECOMMEND_FAILED_INVALID_APK) {
                    ret = PackageManager.INSTALL_FAILED_INVALID_APK;
                } else if (loc == PackageHelper.RECOMMEND_FAILED_INVALID_URI) {
                    ret = PackageManager.INSTALL_FAILED_INVALID_URI;
                } else if (loc == PackageHelper.RECOMMEND_MEDIA_UNAVAILABLE) {
                    ret = PackageManager.INSTALL_FAILED_MEDIA_UNAVAILABLE;
                } else {
                    // Override with defaults if needed.
                    //检查推荐的安装路径,如系统应用不允许安装在sd卡上
                    loc = installLocationPolicy(pkgLite);
                    if (loc == PackageHelper.RECOMMEND_FAILED_VERSION_DOWNGRADE) {
                        ret = PackageManager.INSTALL_FAILED_VERSION_DOWNGRADE;
                    } else if (loc == PackageHelper.RECOMMEND_FAILED_WRONG_INSTALLED_VERSION) {
                        ret = PackageManager.INSTALL_FAILED_WRONG_INSTALLED_VERSION;
                    } else if (!onInt) {
                        // Override install location with flags
                        if (loc == PackageHelper.RECOMMEND_INSTALL_EXTERNAL) {
                            // Set the flag to install on external media.
                            installFlags &= ~PackageManager.INSTALL_INTERNAL;
                        } else if (loc == PackageHelper.RECOMMEND_INSTALL_EPHEMERAL) {
                            if (DEBUG_INSTANT) {
                                Slog.v(TAG, "...setting INSTALL_EPHEMERAL install flag");
                            }
                            installFlags |= PackageManager.INSTALL_INSTANT_APP;
                            installFlags &= ~PackageManager.INSTALL_INTERNAL;
                        } else {
                            // Make sure the flag for installing on external
                            // media is unset
                            installFlags |= PackageManager.INSTALL_INTERNAL;
                        }
                    }
                }
            }
            
            //根据安装位置创建不同的InstallArgs
            final InstallArgs args = createInstallArgs(this);
            mVerificationCompleted = true;
            mIntegrityVerificationCompleted = true;
            mEnableRollbackCompleted = true;
            mArgs = args;

            if (ret == PackageManager.INSTALL_SUCCEEDED) {
                final int verificationId = mPendingVerificationToken++;

                // Perform package verification (unless we are simply moving the package).
                if (!origin.existing) {
                    PackageVerificationState verificationState =
                            new PackageVerificationState(this);
                    mPendingVerification.append(verificationId, verificationState);
                    
                    //完整性验证
                    sendIntegrityVerificationRequest(verificationId, pkgLite, verificationState);
                    ret = sendPackageVerificationRequest(
                            verificationId, pkgLite, verificationState);

                    // If both verifications are skipped, we should remove the state.
                    if (verificationState.areAllVerificationsComplete()) {
                        mPendingVerification.remove(verificationId);
                    }
                }

                if ((installFlags & PackageManager.INSTALL_ENABLE_ROLLBACK) != 0) {
                    // TODO(ruhler) b/112431924: Don't do this in case of 'move'?
                    final int enableRollbackToken = mPendingEnableRollbackToken++;
                    Trace.asyncTraceBegin(
                            TRACE_TAG_PACKAGE_MANAGER, "enable_rollback", enableRollbackToken);
                    mPendingEnableRollback.append(enableRollbackToken, this);

                    Intent enableRollbackIntent = new Intent(Intent.ACTION_PACKAGE_ENABLE_ROLLBACK);
                    enableRollbackIntent.putExtra(
                            PackageManagerInternal.EXTRA_ENABLE_ROLLBACK_TOKEN,
                            enableRollbackToken);
                    enableRollbackIntent.putExtra(
                            PackageManagerInternal.EXTRA_ENABLE_ROLLBACK_SESSION_ID,
                            mSessionId);
                    enableRollbackIntent.setType(PACKAGE_MIME_TYPE);
                    enableRollbackIntent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);

                    // Allow the broadcast to be sent before boot complete.
                    // This is needed when committing the apk part of a staged
                    // session in early boot. The rollback manager registers
                    // its receiver early enough during the boot process that
                    // it will not miss the broadcast.
                    enableRollbackIntent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);

                    mContext.sendOrderedBroadcastAsUser(enableRollbackIntent, UserHandle.SYSTEM,
                            android.Manifest.permission.PACKAGE_ROLLBACK_AGENT,
                            new BroadcastReceiver() {
                                @Override
                                public void onReceive(Context context, Intent intent) {
                                    // the duration to wait for rollback to be enabled, in millis
                                    long rollbackTimeout = DeviceConfig.getLong(
                                            DeviceConfig.NAMESPACE_ROLLBACK,
                                            PROPERTY_ENABLE_ROLLBACK_TIMEOUT_MILLIS,
                                            DEFAULT_ENABLE_ROLLBACK_TIMEOUT_MILLIS);
                                    if (rollbackTimeout < 0) {
                                        rollbackTimeout = DEFAULT_ENABLE_ROLLBACK_TIMEOUT_MILLIS;
                                    }
                                    final Message msg = mHandler.obtainMessage(
                                            ENABLE_ROLLBACK_TIMEOUT);
                                    msg.arg1 = enableRollbackToken;
                                    msg.arg2 = mSessionId;
                                    mHandler.sendMessageDelayed(msg, rollbackTimeout);
                                }
                            }, null, 0, null, null);

                    mEnableRollbackCompleted = false;
                }
            }

            mRet = ret;
        }

这段代码主要用于处理应用程序的安装过程,包括获取应用程序信息、检查存储空间、生成安装参数、启用回滚等。

        @Override
        void handleReturnCode() {
            if (mVerificationCompleted
                    && mIntegrityVerificationCompleted && mEnableRollbackCompleted) {
                    //模拟安装过程并返回结果
                if ((installFlags & PackageManager.INSTALL_DRY_RUN) != 0) {
                    String packageName = "";
                    ParseResult<PackageLite> result = ApkLiteParseUtils.parsePackageLite(
                            new ParseTypeImpl(
                                    (changeId, packageName1, targetSdkVersion) -> {
                                        ApplicationInfo appInfo = new ApplicationInfo();
                                        appInfo.packageName = packageName1;
                                        appInfo.targetSdkVersion = targetSdkVersion;
                                        return mPackageParserCallback.isChangeEnabled(changeId,
                                                appInfo);
                                    }).reset(),
                            origin.file, 0);
                    if (result.isError()) {
                        Slog.e(TAG, "Can't parse package at " + origin.file.getAbsolutePath(),
                                result.getException());
                    } else {
                        packageName = result.getResult().packageName;
                    }
                    try {
                        observer.onPackageInstalled(packageName, mRet, "Dry run", new Bundle());
                    } catch (RemoteException e) {
                        Slog.i(TAG, "Observer no longer exists.");
                    }
                    return;
                }
                if (mRet == PackageManager.INSTALL_SUCCEEDED) {
                    //拷贝apk 如拷贝到data/app下
                    mRet = mArgs.copyApk();
                }
                //处理安装请求 方法中是异步执行
                processPendingInstall(mArgs, mRet);
            }
        }

processPendingInstall

    private void processPendingInstall(final InstallArgs args, final int currentStatus) {
        if (args.mMultiPackageInstallParams != null) {
            args.mMultiPackageInstallParams.tryProcessInstallRequest(args, currentStatus);
        } else {
            PackageInstalledInfo res = createPackageInstalledInfo(currentStatus);
            processInstallRequestsAsync(
                    res.returnCode == PackageManager.INSTALL_SUCCEEDED,
                    Collections.singletonList(new InstallRequest(args, res)));
        }
    }

    // Queue up an async operation since the package installation may take a little while.
    private void processInstallRequestsAsync(boolean success,
            List<InstallRequest> installRequests) {
        mHandler.post(() -> {
            if (success) {
                for (InstallRequest request : installRequests) {
                    request.args.doPreInstall(request.installResult.returnCode);
                }
                synchronized (mInstallLock) {
                    installPackagesTracedLI(installRequests);
                }
                for (InstallRequest request : installRequests) {
                    request.args.doPostInstall(
                            request.installResult.returnCode, request.installResult.uid);
                }
            }
            for (InstallRequest request : installRequests) {
                restoreAndPostInstall(request.args.user.getIdentifier(), request.installResult,
                        new PostInstallData(request.args, request.installResult, null));
            }
        });
    }
    
        @GuardedBy({"mInstallLock", "mLock"})
    private void installPackagesTracedLI(List<InstallRequest> requests) {
        try {
            Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "installPackages");
            installPackagesLI(requests);
        } finally {
            Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
        }
    }


installpackageLI执行安装

    @GuardedBy("mInstallLock")
    private void installPackagesLI(List<InstallRequest> requests) {
        final Map<String, ScanResult> preparedScans = new ArrayMap<>(requests.size());
        final Map<String, InstallArgs> installArgs = new ArrayMap<>(requests.size());
        final Map<String, PackageInstalledInfo> installResults = new ArrayMap<>(requests.size());
        final Map<String, PrepareResult> prepareResults = new ArrayMap<>(requests.size());
        final Map<String, VersionInfo> versionInfos = new ArrayMap<>(requests.size());
        final Map<String, PackageSetting> lastStaticSharedLibSettings =
                new ArrayMap<>(requests.size());
        final Map<String, Boolean> createdAppId = new ArrayMap<>(requests.size());
        boolean success = false;
        try {
            Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "installPackagesLI");
            for (InstallRequest request : requests) {
                // TODO(b/109941548): remove this once we've pulled everything from it and into
                //                    scan, reconcile or commit.
                final PrepareResult prepareResult;
                try {
                    Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "preparePackage");
                    prepareResult =
                            preparePackageLI(request.args, request.installResult);
                } catch (PrepareFailure prepareFailure) {
                    request.installResult.setError(prepareFailure.error,
                            prepareFailure.getMessage());
                    request.installResult.origPackage = prepareFailure.conflictingPackage;
                    request.installResult.origPermission = prepareFailure.conflictingPermission;
                    return;
                } finally {
                    Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
                }
                request.installResult.setReturnCode(PackageManager.INSTALL_SUCCEEDED);
                request.installResult.installerPackageName =
                        request.args.installSource.installerPackageName;

                final String packageName = prepareResult.packageToScan.getPackageName();
                prepareResults.put(packageName, prepareResult);
                installResults.put(packageName, request.installResult);
                installArgs.put(packageName, request.args);
                try {
                    final ScanResult result = scanPackageTracedLI(
                            prepareResult.packageToScan, prepareResult.parseFlags,
                            prepareResult.scanFlags, System.currentTimeMillis(),
                            request.args.user, request.args.abiOverride);
                    if (null != preparedScans.put(result.pkgSetting.pkg.getPackageName(), result)) {
                        request.installResult.setError(
                                PackageManager.INSTALL_FAILED_DUPLICATE_PACKAGE,
                                "Duplicate package " + result.pkgSetting.pkg.getPackageName()
                                        + " in multi-package install request.");
                        return;
                    }
                    createdAppId.put(packageName, optimisticallyRegisterAppId(result));
                    versionInfos.put(result.pkgSetting.pkg.getPackageName(),
                            getSettingsVersionForPackage(result.pkgSetting.pkg));
                    if (result.staticSharedLibraryInfo != null) {
                        final PackageSetting sharedLibLatestVersionSetting =
                                getSharedLibLatestVersionSetting(result);
                        if (sharedLibLatestVersionSetting != null) {
                            lastStaticSharedLibSettings.put(result.pkgSetting.pkg.getPackageName(),
                                    sharedLibLatestVersionSetting);
                        }
                    }
                } catch (PackageManagerException e) {
                    request.installResult.setError("Scanning Failed.", e);
                    return;
                }
            }
            ReconcileRequest reconcileRequest = new ReconcileRequest(preparedScans, installArgs,
                    installResults,
                    prepareResults,
                    mSharedLibraries,
                    Collections.unmodifiableMap(mPackages), versionInfos,
                    lastStaticSharedLibSettings);
            CommitRequest commitRequest = null;
            synchronized (mLock) {
                Map<String, ReconciledPackage> reconciledPackages;
                try {
                    Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "reconcilePackages");
                    reconciledPackages = reconcilePackagesLocked(
                            reconcileRequest, mSettings.mKeySetManagerService);
                } catch (ReconcileFailure e) {
                    for (InstallRequest request : requests) {
                        request.installResult.setError("Reconciliation failed...", e);
                    }
                    return;
                } finally {
                    Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
                }
                try {
                    Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "commitPackages");
                    commitRequest = new CommitRequest(reconciledPackages,
                            mUserManager.getUserIds());
                    commitPackagesLocked(commitRequest);
                    success = true;
                } finally {
                    Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
                }
            }
            executePostCommitSteps(commitRequest);
        } finally {
            if (success) {
                for (InstallRequest request : requests) {
                    final InstallArgs args = request.args;
                    if (args.mDataLoaderType != DataLoaderType.INCREMENTAL) {
                        continue;
                    }
                    if (args.signingDetails.signatureSchemeVersion != SIGNING_BLOCK_V4) {
                        continue;
                    }
                    // For incremental installs, we bypass the verifier prior to install. Now
                    // that we know the package is valid, send a notice to the verifier with
                    // the root hash of the base.apk.
                    final String baseCodePath = request.installResult.pkg.getBaseCodePath();
                    final String[] splitCodePaths = request.installResult.pkg.getSplitCodePaths();
                    final Uri originUri = Uri.fromFile(args.origin.resolvedFile);
                    final int verificationId = mPendingVerificationToken++;
                    final String rootHashString = PackageManagerServiceUtils
                            .buildVerificationRootHashString(baseCodePath, splitCodePaths);
                    broadcastPackageVerified(verificationId, originUri,
                            PackageManager.VERIFICATION_ALLOW, rootHashString,
                            args.mDataLoaderType, args.getUser());
                }
            } else {
                for (ScanResult result : preparedScans.values()) {
                    if (createdAppId.getOrDefault(result.request.parsedPackage.getPackageName(),
                            false)) {
                        cleanUpAppIdCreation(result);
                    }
                }
                // TODO(patb): create a more descriptive reason than unknown in future release
                // mark all non-failure installs as UNKNOWN so we do not treat them as success
                for (InstallRequest request : requests) {
                    if (request.installResult.freezer != null) {
                        request.installResult.freezer.close();
                    }
                    if (request.installResult.returnCode == PackageManager.INSTALL_SUCCEEDED) {
                        request.installResult.returnCode = PackageManager.INSTALL_UNKNOWN;
                    }
                }
            }
            Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
        }
    }
  1. 首先,创建了一些用于存储安装过程中的结果和临时数据的Map对象,如preparedScans、installArgs、installResults等。
  2. 创建了一个createdAppId的Map对象,用于存储已创建的应用程序ID。
  3. 设置一个布尔变量success,用于标记安装过程是否成功。
  4. 开始一个跟踪标记为TRACE_TAG_PACKAGE_MANAGER的跟踪事件。
  5. 遍历requests列表中的每个InstallRequest对象。
  6. 在每个InstallRequest对象中执行以下操作:
  • 调用preparePackageLI()方法准备安装包,并将结果存储在prepareResult中。
  • 如果准备过程中发生PrepareFailure异常,则将异常信息设置到installResult中,并返回。
  • 将installResult的返回码设置为PackageManager.INSTALL_SUCCEEDED。
  • 将installResult的安装程序包名设置为installSource的安装程序包名。
  1. 结束跟踪标记为TRACE_TAG_PACKAGE_MANAGER的跟踪事件。
  2. 在mLock同步块中执行以下操作:
  • 调用reconcilePackagesLocked()方法对准备的安装包进行调和,并将结果存储在reconciledPackages中。
  • 如果调和过程中发生ReconcileFailure异常,则将异常信息设置到每个InstallRequest对象的installResult中,并返回。
  • 创建一个CommitRequest对象,并将调和结果、用户ID等信息传递给它。
  • 在mLock同步块中执行以下操作:
  • 调用commitPackagesLocked()方法提交安装包,并将结果存储在commitRequest中。
  • 将success设置为true,表示安装过程成功。
  • 执行executePostCommitSteps()方法,执行提交后的步骤。
  1. 最后,如果安装过程成功,则执行以下操作:
  • 遍历requests列表中的每个InstallRequest对象。
  • 如果args.mDataLoaderType为DataLoaderType.INCREMENTAL,则执行以下操作:
  • 关闭installResult中的freezer。
  • 将installResult的返回码设置为PackageManager.INSTALL_UNKNOWN。
  1. 返回。

4、Intent及IntentFilter

主要是PMS里的queryIntentActivities、queryIntentServices、queryBroadcastReceivers这几个方法
书中和Android11的差距有点大,看不懂 ,后面再看。
书中提到的mActivities这个变量在Android11是没有的,但是Android11有mInstrumentation,这是个存储组件的信息的Map,或许在这里面会存Intent相关的信息。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1177224.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

开发抖音群控软件的费用在什么范围内?

随着抖音等社交媒体的普及&#xff0c;越来越多的企业和个人开始注重在社交媒体平台上的营销和推广&#xff0c;而开发一款抖音群控软件&#xff0c;可以帮助用户更好地管理和运营其在抖音平台上的账号&#xff0c;提高账号的曝光率和关注度&#xff0c;那么&#xff0c;开发一…

速卖通发布公告,屏蔽对欧洲资质和标签不合规商品——站斧浏览器

近日全球速卖通发布关于公告&#xff0c;根据欧盟法规要求&#xff0c;商品卖向欧盟和英国市场需要满足欧盟商品资质合规的要求。对于资质和标签不满足合规要求的商品&#xff0c;平台已经陆续开始执行屏蔽管控&#xff0c;卖家为了保障欧盟市场的正常售卖&#xff0c;需要尽快…

【计算机网络】数据链路层-MAC和ARP协议

文章目录 1. 认识以太网2. MAC协议MAC帧的格式MAC地址和IP地址的区别MTU 3. 局域网通信原理碰撞检测和避免 4. ARP协议ARP数据报的格式ARP缓存 1. 认识以太网 网络层解决的是跨网络点到点传输的问题&#xff0c;数据链路层解决的是同一网络中的通信。 数据链路层负责在同一局域…

Power Apps-1.1通过函数修改组件属性

修改字体颜色 1.点击想要根据条件变化的文本组件&#xff0c;出现右侧边栏后&#xff0c;点击下方的“颜色”标题 2.修改函数设置 If(判断条件,判断结果为true时执行的颜色,判断结果为false时执行的颜色) 颜色代码可参考&#xff1a; Power Apps 中的颜色和边框属性 - Power…

单点登录与OAuth2.0 的区别

前言&#xff1a;SSO是Single Sign On(单点登录)的缩写&#xff0c;OAuth是Open Authority&#xff08;开放授权&#xff09;&#xff0c;这两者都是使用令牌的方式来代替用户密码访问应用。流程上来说他们非常相似&#xff0c;但概念上又十分不同。很多人会将其混为一谈&#…

操作系统·操作系统引论

1.1 操作系统的目标和作用 1.目前常见操作系统&#xff1a; 微软&#xff1a;Windows系列&#xff08;以前MS-DOS&#xff09; UNIX&#xff1a;Solaris, AIX, HP UX, SVR4, BSD, ULTRIX 自由软件&#xff1a;Linux, freeBSD, Minix IBM: AIX, zOS(OS/390), OS/2, OS/400, PC…

JAVA客户端使用账号密码调用influxdb2报错:{“code“:“unauthorized“,“message“:“Unauthorized“}

问题&#xff1a;JAVA客户端访问influxdb2报错 说明&#xff1a;当前influxdb版本&#xff1a;2.6.1 使用依赖&#xff1a; <dependency><groupId>org.influxdb</groupId><artifactId>influxdb-java</artifactId><version>2.10</vers…

提升企业知名度必备!媒体发稿的5个关键要点

近年来&#xff0c;媒体发稿成为企业提升知名度和品牌形象的重要手段。无论是大型企业还是中小企业&#xff0c;都倾向于选择媒体发稿来扩大影响力。然而&#xff0c;很多企业在发稿后并没有如预期般获得良好效果。这可能是因为他们没有掌握正确的技巧。那么&#xff0c;在媒体…

带你一文搞懂 Linux 网络 Phy 驱动

概述 上图来自 瑞昱半导体 (RealTek) 的 RTL8201F 系列网卡 PHY 芯片手册。按OSI 7层网络模型划分&#xff0c;网卡PHY 芯片(图中的RTL8201F)位于物理层&#xff0c;对应的软件层就是本文讨论的 PHY 驱动层&#xff1b;而 MAC 位于 数据链路层&#xff0c;也是通常软件上所说的…

【黑马程序员】Git 的概述

文章目录 前言一、概述1. 开发中的实际场景2. 版本控制器的方式3. SVN4. Git5. Git 工作流程图 总结 前言 跟着B站的黑马程序员学习 Git&#xff0c;语言为java&#xff0c;目前是第一个内容 课程传送门&#xff1a;Git 的概述 一、概述 1. 开发中的实际场景 场景一&#xf…

高效解决香港服务器负载过高的方法

​  当我们在使用香港服务器时&#xff0c;有时会遇到服务器负载过高的问题。这会导致网站加载速度变慢甚至无法正常使用。为了解决这个问题&#xff0c;我们需要采取一些高效的方法来提升服务器的负载能力。 1.考虑对服务器进行升级维护。通过增加硬件资源&#xff0c;如CPU…

综合布线可视化管理系统价值分析

传统综合布线管理&#xff0c;全部依靠手工登记&#xff0c;利用标签标示线缆&#xff0c;利用文档资料记录链路的连接和变更&#xff0c;高度依赖网络管理员的管理能力&#xff0c;维护效率低下。同时&#xff0c;网络接入故障和非法接入难以及时发现。在以往的文章中小编一直…

灵活调整宣传策略,媒体发稿和新闻发布的优势所在

企业在当今信息爆炸的时代&#xff0c;要想在市场竞争中脱颖而出&#xff0c;提高公信力是至关重要的。而媒体发稿和新闻发布是提升企业公信力的重要手段之一。下面将从门户网站的权威展示、搜索引擎排名的提升、内容的持续稳定有效性、内容的可改性以及协助增加网站流量等方面…

深度剖析.locked1勒索病毒的威胁:如何保护您的数据

导言&#xff1a; .locked1勒索病毒是当今数字时代中最神秘的网络威胁之一。这种恶意软件以其毫不留情的数据加密技术而著称&#xff0c;常通过欺诈邮件附件、恶意链接或漏洞利用等方式传播。本文91数据恢复将深入探讨.locked1勒索病毒的运作方式&#xff0c;提供数据恢复的方…

北京陪诊小程序|陪诊系统开发|陪诊小程序未来发展不可小觑

近几年随着互联网快速发展&#xff0c;各行业领域都比较注重线上服务系统&#xff0c;通过陪诊小程序开发可以满足更多用户使用需求&#xff0c;同时还能提高用户使用体验。现在陪诊类的软件应用得到全面推广&#xff0c;在医疗行业当中陪诊小程序更贴近用户生活&#xff0c;可…

【QT】QT自定义类封装,附简单例子

提升为主要是可以使用自定义的部件&#xff0c;所以先要写好自定义控件后&#xff0c;再添加&#xff0c;在频繁使用同一控件时&#xff0c;的确非常的高效。 下面以自定义的QPushButton作一个很简单的例子。 先新建默认Qt Widgets Application项目 一、自定义类 建立项目后…

以“和合”酒礼开启“全国理性饮酒周”,五粮液勇担社会责任赋能美好生活

执笔 | 尼 奥 编辑 | 萧 萧 10月31日&#xff0c;由中国酒业协会主办&#xff0c;酒与社会责任促进工作委员会承办&#xff0c;五粮液集团公司协办的“2023年中国酒业协会酒与社会责任促进工作委员会年会暨2023全国理性饮酒宣传周新闻发布会”在成都举行。 酒&#xff0c…

大数据趣味学习探讨(二):我是怎么坚持学习的

CSDN话题挑战赛第2期 参赛话题&#xff1a;大数据趣味学习探讨 文章目录 要不要学&#xff0c;为什么要学大数据&#xff0c;最好的机会没有之一 一、根本性的问题 1、打仗最重要的是什么&#xff1f; 2、为什么总是知行不一 二、大数据到底好在哪 1、结论 2、大数据为…

机器人制作开源方案 | 管内检测维护机器人

一、作品简介 作者&#xff1a;李泽彬&#xff0c;李晋晟&#xff0c;杜张坤&#xff0c;禹馨雅 单位&#xff1a;运城学院 指导老师&#xff1a;薛晓峰 随着我国的社会主义市场经济的飞速发展和科学技术的革新&#xff0c;各行各业的发展越来越离不开信息化和网络化的…

数据结构 - 全貌总结

目录 一. 前言 二. 分类 三. 常见的线性和非线性结构 一. 前言 数据结构是计算机存储、组织数据的方式。一种好的数据结构可以带来更高的运行或者存储效率。数据在内存中是呈线性排列的&#xff0c;但是我们可以使用指针等道具&#xff0c;构造出类似“树形”等复杂结构。 数…