Android中persistent属性的简介

Android  2020年11月21日 pm10:59发布4年前 (2020)更新 城堡大人
112 0 0

前言

Android中,有些应用没有通过Service或者Broadcast等启动他,但Application还是被启动了。

经过查阅资料和看代码,发现android:persistent="true"的妙用之处。

实现Application,然后AndroidManifest.xml中注册Application,并在其属下中添加android:persistent="true",如下:

    <application
        android:allowBackup="true"
        android:name="com.water.app.WaterApp"
        android:icon="@mipmap/ic_launcher"
        android:persistent="true"
        android:label="@string/app_name"
        android:roundIcon="@mipmap/ic_launcher_round"
        android:supportsRtl="true"
        android:theme="@style/AppTheme">

       ......

    </application>

下面我们来简单的分析一下是不是所有应用设置android:persistent="true"都是有效的。

正文

android:persistent="true"对任何应用有效么?
  1. ActivityManagerService.java

目录地址:\frameworks\base\services\core\java\com\android\server\am\ActivityManagerService.java

    public void systemReady(final Runnable goingCallback, TimingsTraceLog traceLog) {


    .....

    startPersistentApps(PackageManager.MATCH_DIRECT_BOOT_AWARE);

    .....

    }
    void startPersistentApps(int matchFlags) {
        if (mFactoryTest == FactoryTest.FACTORY_TEST_LOW_LEVEL) return;

        synchronized (this) {
            try {
                final List<ApplicationInfo> apps = AppGlobals.getPackageManager()
                        .getPersistentApplications(STOCK_PM_FLAGS | matchFlags).getList();
                for (ApplicationInfo app : apps) {
                    if (!"android".equals(app.packageName)) {
                        addAppLocked(app, null, false, null /* ABI override */);
                    }
                }
            } catch (RemoteException ex) {
            }
        }
    }
  1. PackageManagerService.java

目录地址:frameworks\base\services\core\java\com\android\server\pm\PackageManagerService.java

    @Override
    public @NonNull ParceledListSlice<ApplicationInfo> getPersistentApplications(int flags) {
        if (getInstantAppPackageName(Binder.getCallingUid()) != null) {
            return ParceledListSlice.emptyList();
        }
        return new ParceledListSlice<>(getPersistentApplicationsInternal(flags));
    }

    private @NonNull List<ApplicationInfo> getPersistentApplicationsInternal(int flags) {
        final ArrayList<ApplicationInfo> finalList = new ArrayList<ApplicationInfo>();

        // reader
        synchronized (mPackages) {
            final Iterator<PackageParser.Package> i = mPackages.values().iterator();
            final int userId = UserHandle.getCallingUserId();
            while (i.hasNext()) {
                final PackageParser.Package p = i.next();
                if (p.applicationInfo == null) continue;

                final boolean matchesUnaware = ((flags & MATCH_DIRECT_BOOT_UNAWARE) != 0)
                        && !p.applicationInfo.isDirectBootAware();
                final boolean matchesAware = ((flags & MATCH_DIRECT_BOOT_AWARE) != 0)
                        && p.applicationInfo.isDirectBootAware();

                if ((p.applicationInfo.flags & ApplicationInfo.FLAG_PERSISTENT) != 0
                        && (!mSafeMode || isSystemApp(p))
                        && (matchesUnaware || matchesAware)) {
                    PackageSetting ps = mSettings.mPackages.get(p.packageName);
                    if (ps != null) {
                        ApplicationInfo ai = PackageParser.generateApplicationInfo(p, flags,
                                ps.readUserState(userId), userId);
                        if (ai != null) {
                            finalList.add(ai);
                        }
                    }
                }
            }
        }

        return finalList;
    }

在PackageManagerService.java解析apk时会把带有ApplicationInfo.FLAG_PERSISTENT的apk解析出来。

上面也有是否是系统应用和安全模式判断,如下代码:

    if ((p.applicationInfo.flags & ApplicationInfo.FLAG_PERSISTENT) != 0
            && (!mSafeMode || isSystemApp(p))
            && (matchesUnaware || matchesAware)) {
        PackageSetting ps = mSettings.mPackages.get(p.packageName);
        if (ps != null) {
            ApplicationInfo ai = PackageParser.generateApplicationInfo(p, flags,
                    ps.readUserState(userId), userId);
            if (ai != null) {
                finalList.add(ai);
            }
        }
    }

也就是非系统应用需要再[非安全模式]下才可以是启动,如果是[安全模式]且[非系统应用],即使你设置了persistent属性也是无法被启动Application、

总结

需要android:persistent="true"有效,除了设置了这个属性,还需要满足下面中的一个。

  1. 非安全模式
  2. 系统应用

参考文章

  1. android persistent属性研究
  2. Android应用的persistent属性

 历史上的今天

  1. 2024: Android截图命令总结(0条评论)
  2. 2019: 王小波:写给新的一年(0条评论)
版权声明 1、 本站名称: 笔友城堡
2、 本站网址: https://www.biumall.com/
3、 本站部分文章来源于网络,仅供学习与参考,如有侵权,请留言

暂无评论

暂无评论...

随机推荐

Android之获取图片高宽方法的简单记录

前言本文非原创,大佬的基础上进行修改和调试,下面三种方式我都测试过。感谢大佬们分享。好记性不如烂笔头总结如果只获取高宽,推荐使用BitmapFactory.Options如果要加载图片和获取高宽,推荐使用Glide如果只是加载jpg图片,可以考虑ExifInterface,否则不推荐...

ThreadPoolExecutor简单记录

前言线程经常用,线程池也用,但在于如何使用,没有记录一下。本文参考别人文章整理。正文使用线程池的好处降低内存资源消耗。通过重复利用已创建的线程降低线程创建和销毁造成的消耗。提高响应速度。在线程池中的线程都是已经被创建好的,我们的任务直接获取一个空闲的线程就能够被执行了提高线程的可管...

[摘]修改cmd编码格式

前言命令行显示中文乱码,大多是由于字符编码不匹配导致。有时候需要改变cmd的字符编码。本文摘抄,记录于此。好记性不如烂笔头。正文查看cmd的字符编码,在cmd中输入chcpchcp活动代码页: 936活动代码页936,指的就是GBK如果需要改变字符编码。# 设置编码格式为U...

[摘]Android判断顶部Activity的包名等

前言本文摘抄,具体来源看末尾连接,记录于此。好记性不如烂笔头。小结在实际中,发现使用[获取顶层Activity]的第一个方式存在问题,偶尔获取的顶层activity是错误的。正文判断当前是不是桌面 public static boolean isHome(Context con...

[摘]CMakeLists.txt常用语法之常用命令

前言cmake 是一个跨平台、开源的构建系统。它是一个集软件构建、测试、打包于一身的软件。它使用与平台和编译器独立的配置文件来对软件编译过程进行控制。正文下面介绍常用的命令制定cmake最小版本cmake_minimum_required(VERSION 3.4.1)这行命令是可选的...

Android (/sys/路径)属性文件节点值的读写

Android (/sys/路径)属性文件节点值的读写,在朋友代码基础上增加了finally 代码。如下,大致如此 /** * 文件的读取权限记得添加咯 */ /** * 某个节点写入值 * * @param value...