Quantcast
Channel: CSDN博客移动开发推荐文章
Viewing all articles
Browse latest Browse all 5930

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

$
0
0

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

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

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

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

这里只列举一部分。

后缀 方法名
LI collectCertificatesLI()
installPackageLI()
scanPackageLI()
scanDirLI()
LIF deletePackageLIF()
deleteSystemPackageLIF()
clearApplicationUserDataLIF()
clearAppDataLIF()
LP verifySignaturesLP()
checkPermissionTreeLP()
findPermissionTreeLP()
findPersistentPreferredActivityLP()
LPw grantPermissionsLPw()
updatePermissionsLPw()
enableSystemPackageLPw()
setInstallerPackageNameLPw()
LPr getRequiredInstallerLPr()
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>
 */
作者:u013553529 发表于2017/3/14 0:52:56 原文链接
阅读:136 评论:0 查看评论

Viewing all articles
Browse latest Browse all 5930

Trending Articles



<script src="https://jsc.adskeeper.com/r/s/rssing.com.1596347.js" async> </script>