PackageManagerService中的方法名中的LI、LIF、LPw、LPr的含义

https://blog.youkuaiyun.com/u013553529/article/details/61962439


PackageManagerService中的方法名中的LI、LIF、LPw、LPr的含义

注1:本文参考Android 7.1.1r13源码中的PackageManagerService的说明。 
这个说明在Android6.0.1中是没有的。

注2:本文中PackageManagerService简称为PMS。

1. 方法名后缀为LI、LIF、LPw、LPr的方法

这里只列举一部分。

后缀方法名
LIcollectCertificatesLI() 
installPackageLI() 
scanPackageLI() 
scanDirLI()
LIFdeletePackageLIF() 
deleteSystemPackageLIF() 
clearApplicationUserDataLIF() 
clearAppDataLIF()
LPverifySignaturesLP() 
checkPermissionTreeLP() 
findPermissionTreeLP() 
findPersistentPreferredActivityLP()
LPwgrantPermissionsLPw() 
updatePermissionsLPw() 
enableSystemPackageLPw() 
setInstallerPackageNameLPw()
LPrgetRequiredInstallerLPr() 
verifyPackageUpdateLPr() 
normalizePackageNameLPr() 
needsNetworkVerificationLPr()

2. PMS中的两个锁

要想弄明白方法名中的LI、LIF、LPw、LPr的含义,需要先了解PackageManagerService内部使用的两个锁。因为LI、LIF、LPw、LPr中的L,指的是Lock,而后面跟的I和P指的是两个锁,I表示mInstallLock同步锁。P表示mPackages同步锁。LPw、LPr中的w表示writing,r表示reading。LIF中的F表示Freeze。

mPackages同步锁,是指操作mPackages时,用synchronized (mPackages) {}保护起来。mPackages同步锁用来保护内存中已经解析的包信息和其他相关状态mPackages同步锁是细粒度的锁,只能短时间持有这个锁,因为争抢mPackages锁的请求很多,短时间持有mPackages锁,可以让其他请求等待的时间短些。

mInstallLock同步锁,是指安装App的时候,对安装的处理要用synchronized (mInstaller) {}保护起来。mInstallLock同步锁,用来保护所有对installd的访问。installd通常包含对应用数据的繁重操作。

由于installd是单线程的,并且installd的操作通常很慢,所以在已经持有mPackages同步锁的时候,千万不要再请求mInstallLock同步锁。反之,在已经持有mInstallLock同步锁的时候,可以去请求mPackages同步锁。

用代码表示出来,是这样的:

注意:不允许的情况:

synchronized (mPackages) {
synchronized (mInstaller) {
    // 这种情况是不允许的。因为Install的处理时间会很长,导致对mPackages锁住的时间加长,会使得其他对mPackages操作的请求处于长时间等待。
}
}
  • 1
  • 2
  • 3
  • 4
  • 5

允许的情况:

synchronized (mInstaller) {
synchronized (mPackages) {
    // 这种情况是允许的。因为mPackages处理完之后,其他对mPackages操作的请求可以对mPackages处理,不需要等待太久。
    // 由于处理Install的时间本身很长,synchronized (mPackages)又较快,所以不会对原本长时间持有mInstaller锁的情况有大的影响。
}
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

注:关于Java同步的官方说明:https://docs.oracle.com/javase/tutorial/essential/concurrency/sync.html

3. 方法名中的LI、LIF、LPw、LPr的含义

方法名使用方式
fooLI()调用fooLI(),必须先持有mInstallLock锁。
fooLIF()调用fooLIF(),必须先持有mInstallLock锁,并且正在被修改的包(package)必须被冻结(be frozen)。
fooLPr()调用fooLPr(),必须先持有mPackages锁,并且只用于操作。
fooLPw()调用fooLPw(),必须先持有mPackages锁,并且只用于操作。


举一些例子:

例1:方法名中带有LP的方法:verifySignaturesLP()

使用verifySignaturesLP()的时候,要加上synchronized (mPackages)或者在其他带LP的方法中使用。

    synchronized (mPackages) {
        //省略其他代码
        verifySignaturesLP(pkgSetting, pkg);
    }
  • 1
  • 2
  • 3
  • 4

例2: 方法名中带有LI的方法:installPackageLI()和installPackageTracedLI()

使用installPackageTracedLI()的时候,加上synchronized (mInstallLock)

    synchronized (mInstallLock) {
        installPackageTracedLI(args, res);
    }
  • 1
  • 2
  • 3

调用installPackageLI()的时候,没有加上synchronized (mInstallLock),但是在带有LI的方法中使用,例如installPackageTracedLI()中调用installPackageLI():

    private void installPackageTracedLI(InstallArgs args, PackageInstalledInfo res) {
        try {
            installPackageLI(args, res);
        }
        ...
    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

4. @GuardedBy 注解

在代码中还有一种@GuardedBy注解(com.android.internal.annotations.GuardedBy),用于标记哪些变量要用同步锁保护起来。

例1:@GuardedBy(“mPackages”)

    @GuardedBy("mPackages")
    private boolean mDexOptDialogShown;
  • 1
  • 2

上面的@GuardedBy注解表示所有使用mDexOptDialogShown的地方,都要用synchronized (mPackages)保护起来,以保证并发时不会有错误。 
例如,

    synchronized (mPackages) {
        mDexOptDialogShown = true;
    }

    synchronized (mPackages) {
        dexOptDialogShown = mDexOptDialogShown;
    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

例2:@GuardedBy(“mInstallLock”)

@GuardedBy("mInstallLock")注解的变量:mInstaller。如下:

    @GuardedBy("mInstallLock")
    final Installer mInstaller;
  • 1
  • 2

所以,使用mInstaller的地方都要用synchronized (mInstallLock)保护起来。 
例如,

    synchronized (mInstallLock) {
        mSettings.createNewUserLI(this, mInstaller, userId);
    }

    synchronized (mInstallLock) {
        mInstaller.createUserData(volumeUuid, userId, userSerial, flags);
    }

    synchronized (mInstallLock) {
        // 注意这里的info.args是InstallArgs。PMS中对InstallArgs的处理,也是用mInstallLock锁保护起来的。
        info.args.doPostDeleteLI(true);
    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12

PMS中还有synchronized (mInstaller)这种同步锁。不知道是笔误,还是就是这样子的。

    synchronized (mInstaller) {
        try {
            mInstaller.moveCompleteApp(move.fromUuid, move.toUuid, move.packageName,
                    move.dataAppName, move.appId, move.seinfo, move.targetSdkVersion);
        }
        ...
    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
    synchronized (mInstaller) {
        for (int userId : installedUserIds) {
            if (!getPackageSizeInfoLI(packageName, userId, stats)) {
                freezer.close();
                ...
            }
        }
    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

需要注意的是:在有的编译环境中可能并不检查@GuardedBy注解,即标有@GuardedBy注解的变量也可能会出现错误用法(即,没有被同步锁保护起来)。某些静态分析工具(例如FindBug)可能会检查@GuardedBy注解,以保证相关变量被正确的使用(即,被同步锁保护起来)。

注:FindBug中检查的GuardedBy注解,是net.jcip.annotations.GuardedBy,不是Android中的com.android.internal.annotations.GuardedBy

5. 附:PMS中的原始内容

/**
 * Keep track of all those APKs everywhere.
 * <p>
 * Internally there are two important locks:
 * <ul>
 * <li>{@link #mPackages} is used to guard all in-memory parsed package details
 * and other related state. It is a fine-grained lock that should only be held
 * momentarily, as it's one of the most contended locks in the system.
 * <li>{@link #mInstallLock} is used to guard all {@code installd} access, whose
 * operations typically involve heavy lifting of application data on disk. Since
 * {@code installd} is single-threaded, and it's operations can often be slow,
 * this lock should never be acquired while already holding {@link #mPackages}.
 * Conversely, it's safe to acquire {@link #mPackages} momentarily while already
 * holding {@link #mInstallLock}.
 * </ul>
 * Many internal methods rely on the caller to hold the appropriate locks, and
 * this contract is expressed through method name suffixes:
 * <ul>
 * <li>fooLI(): the caller must hold {@link #mInstallLock}
 * <li>fooLIF(): the caller must hold {@link #mInstallLock} and the package
 * being modified must be frozen
 * <li>fooLPr(): the caller must hold {@link #mPackages} for reading
 * <li>fooLPw(): the caller must hold {@link #mPackages} for writing
 * </ul>
 * <p>
 * Because this class is very central to the platform's security; please run all
 * CTS and unit tests whenever making modifications:
 *
 * <pre>
 * $ runtest -c android.content.pm.PackageManagerTests frameworks-core
 * $ cts-tradefed run commandAndExit cts -m AppSecurityTests
 * </pre>
 */
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33

<think>嗯,用户之前问过关于在Android系统中限制应用安装权限的问题,我之前给出了基于修改AOSP代码的解决方案,特别是涉及到PackageManagerService中的installPackageAsUser方法。现在用户反馈在Android 14里找不到这个方法,想知道是不是有变化。首先,我需要确认这个方法的变更历史。 首先,回忆一下Android版本的变化。Android的每个大版本都会有代码结构的调整,特别是像PackageManagerService这样的核心服务。用户提到的是Android 14,也就是UpsideDownCake版本。我需要检查AOSP的代码库,看看installPackageAsUser是否存在,或者是否有重命名、拆分的情况。 根据之前的知识,Android 10之后,Google开始将部分代码模块化,并迁移到新的类或包中。例如,在Android 12中,PackageManagerService被拆分成多个类,比如PackageManagerServiceUtils或者不同的模块。可能Android 14中这个方法被移动到了其他位置,或者被拆分成更细粒度的方法。 然后,用户可能在进行系统定制时遇到了问题,无法找到原有的方法,导致他们的修改无法进行。他们可能需要知道新的方法名称或者调用链,以便在正确的位置添加权限检查逻辑。 接下来,我需要确认在Android 14中,应用安装流程的具体变化。根据AOSP的文档或代码提交记录,可能installPackageAsUser被废弃,取而代之的是其他方法,比如通过PackageInstallerService或Session来处理安装请求。例如,在较新的版本中,安装过程可能更多地依赖于Session的提交,而不是直接调用PackageManagerService的方法。 此外,用户可能需要了解如何在新版本中找到替代的拦截点。比如,在Android 14中,安装请求可能由PackageInstaller的Session处理,所以权限检查应该放在Session的创建或提交阶段。需要指导用户如何在这些新位置添加白名单检查。 同时,用户可能对Android版本之间的差异不太熟悉,需要解释清楚变更的原因,以及如何调整他们的定制代码以适应新版本。可能还需要提供示例代码片段,展示在Android 14中应该修改哪些类和方法。 另外,用户可能没有意识到除了源码修改,还有其他替代方案,比如使用Device Policy Controller (DPC) 或者管理API来实现类似的功能,而无需深度定制系统。特别是如果他们无法访问AOSP代码或无法进行系统级修改时,这些替代方案可能更可行。 最后,我需要总结这些点,以清晰的方式回应用户的问题,确保他们理解Android 14中的变化,并提供具体的解决方案和代码示例,帮助他们调整原有的实现方案。</think>在 Android 14(API 34)中,Google 对应用安装流程进行了重构,**`PackageManagerService` 中的 `installPackageAsUser` 方法已被移除**,取而代之的是更模块化的设计。以下是关键变化和适配方案: --- ### 为什么找不到 `installPackageAsUser`? 1. **代码重构** Android 14 将安装逻辑进一步拆分到 `PackageInstallerService` 和 `InstallPackageHelper` 等类中,以降低 `PackageManagerService` 的复杂度。 2. **Session 驱动安装** 所有安装流程(包括 ADB、应用商店、文件管理器)均通过 `PackageInstaller.Session` 提交,入口方法改为 `createSession` 或 `commitSession`。 --- ### 新拦截点与适配方案 #### 1. 拦截 `PackageInstaller.Session` 提交 **目标文件**: `AOSP/frameworks/base/services/core/java/com/android/server/pm/InstallPackageHelper.java` (或 `PackageInstallerService.java`,具体版本可能有差异) **修改方法**: 在 `commitSession` 方法中检查调用者权限: ```java // Android 14 示例代码 @Override public void commitSession( @NonNull PackageInstaller.SessionInfo sessionInfo, boolean forTransfer) { // 获取调用者包名 final int callingUid = Binder.getCallingUid(); String callerPkg = getPackageNameFromUid(callingUid); // 定义白名单(例如:com.example.allow.installer) List<String> allowedInstallers = Arrays.asList("com.example.allow.installer"); // 检查权限 if (!allowedInstallers.contains(callerPkg)) { throw new SecurityException("Caller " + callerPkg + " is not allowed to install packages!"); } // 原逻辑继续执行... } ``` --- #### 2. 控制 `PackageInstaller` 的 Session 创建 **文件路径**: `AOSP/frameworks/base/services/core/java/com/android/server/pm/PackageInstallerService.java` **拦截点**: 在 `createSession` 方法中验证调用者身份: ```java @Override public int createSession(SessionParams params, String installerPackageName, int userId) { // 白名单校验 List<String> allowedPackages = Arrays.asList("com.example.allow.installer"); if (!allowedPackages.contains(installerPackageName)) { Log.e(TAG, "Blocked installation attempt from: " + installerPackageName); throw new SecurityException("Unauthorized installer"); } // 继续原有逻辑... return super.createSession(params, installerPackageName, userId); } ``` --- #### 3. 禁用非白名单的安装来源(Android 14 新增限制) 在 `PackageManagerService` 中强化来源检查: ```java // 文件路径: // AOSP/frameworks/base/services/core/java/com/android/server/pm/PackageManagerService.java private boolean isInstallSourceAllowed(String packageName) { // 系统应用或白名单应用允许安装 return isSystemApp(packageName) || getWhiteList().contains(packageName); } // 自定义白名单 private List<String> getWhiteList() { return Arrays.asList("com.android.vending", "com.example.allow.installer"); } ``` --- ### 针对 Android 14 的注意事项 1. **权限声明变化** `INSTALL_PACKAGES` 权限已被进一步限制,需结合 `MANAGE_INSTALL_SOURCES` 权限控制。 2. **ADB 安装的特殊处理** ADB 安装 (`pm install`) 现在通过 `Shell` 身份调用,若需拦截,需修改 `RootPackageInstaller` 相关逻辑。 3. **模块化架构影响** 安装逻辑分散在多个类中,需同时检查以下关键类: - `InstallPackageHelper.java` - `PackageInstallerService.java` - `PackageSessionVerifier.java` --- ### 替代方案(无需修改 AOSP) 如果无法深度定制系统,可通过 **`DevicePolicyManager`** 实现近似控制(需用户主动授权): ```kotlin // 在设备管理应用中配置白名单 val dpm = context.getSystemService(DevicePolicyManager::class.java) dpm.setPermittedCrossProfilePackages(adminComponentName, listOf("com.example.allow.installer")) ``` --- ### 适配建议 1. **查阅 AOSP 官方文档** Android 14 引入了 [PackageManager Modularization](https://source.android.com/docs/core/ota/modular-system/packagemanager-modularization),需关注新架构设计。 2. **使用动态调试** 通过 `adb logcat | grep 'PackageManager'` 跟踪安装流程的调用栈,定位最新拦截点。 3. **版本兼容性处理** 建议使用条件编译,为不同 Android 版本保留不同实现: ```java #if (PLATFORM_SDK_VERSION >= 34) // Android 14+ 逻辑 #else // 旧版本逻辑 #endif ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值