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

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操作的请求处于长时间等待。
}
}

允许的情况:

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

注:关于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);
    }

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

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

    synchronized (mInstallLock) {
        installPackageTracedLI(args, res);
    }

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

    private void installPackageTracedLI(InstallArgs args, PackageInstalledInfo res) {
        try {
            installPackageLI(args, res);
        }
        ...
    }

4. @GuardedBy 注解

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

例1:@GuardedBy(“mPackages”)

    @GuardedBy("mPackages")
    private boolean mDexOptDialogShown;

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

    synchronized (mPackages) {
        mDexOptDialogShown = true;
    }

    synchronized (mPackages) {
        dexOptDialogShown = mDexOptDialogShown;
    }

例2:@GuardedBy(“mInstallLock”)

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

    @GuardedBy("mInstallLock")
    final Installer mInstaller;

所以,使用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);
    }

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

    synchronized (mInstaller) {
        try {
            mInstaller.moveCompleteApp(move.fromUuid, move.toUuid, move.packageName,
                    move.dataAppName, move.appId, move.seinfo, move.targetSdkVersion);
        }
        ...
    }
    synchronized (mInstaller) {
        for (int userId : installedUserIds) {
            if (!getPackageSizeInfoLI(packageName, userId, stats)) {
                freezer.close();
                ...
            }
        }
    }

需要注意的是:在有的编译环境中可能并不检查@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>
 */
  • 5
    点赞
  • 31
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值