android随笔之directBootAware模式

一. 需求场景

开机需要第一时间快速启动指定app

二. 需求分析

在Android 6.0及之前,在开机启动到锁屏界面时,所有程序阻塞,等待用户解锁(即使未设置开机密码,也需要滑屏解锁)后才会继续。
Android 7.0引入的新特性:Direct Boot Mode:设备启动后进入的一个新模式,直到用户解锁(unlock)设备此阶段结束。
Direct Boot模式下,仅限于运行一些关键的、紧急的APP,比如:
Apps that have scheduled notifications, such as alarm clock apps. //AlarmClock操作
Apps that provide important user notifications, like SMS apps. //重要通知
Apps that provide accessibility services, like Talkback. //特殊服务

另外需要注意的是,Direct Boot Mode下使用一种新的存储空间:Device Protected Storage。在正常模式下是看不到这个空间的数据的,所以在Direct Boot Mode下启动app,也是需要Device Protected Storage的访问权限。

所以要想在android 7.0及以后的系统上实现开机启动指定app,app必须打开directBootAware模式。

三. 实现方法

1. app修改

为了让该应用能够在用户解锁设备之前运行,必须在AndroidManifest中将application及启动的组件显式标记为支持直接启动:

<application
    ......
    android:directBootAware="true"
    android:defaultToDeviceProtectedStorage="true">

    <activity
        ......  
        android:directBootAware=”true”
	    ......
	/activity>
    <!--also can use at provider or receiver or service -->

    ......

2. 如果无法修改app,framework也可以针对特定app进行修改

我们可以在parse package的时候,强制把对应的包名及要启动的组件强制设置directBootAware

android版本不同,可能位置有点差异,比如

android 11是在

framework/base/core/java/android/content/pm/parsing/component/ParsedMainComponentUtils.java解析component

    @NonNull
    @VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE)
    static <Component extends ParsedMainComponent> ParseResult<Component> parseMainComponent(
            Component component, String tag, String[] separateProcesses, ParsingPackage pkg,
            TypedArray array, int flags, boolean useRoundIcon, ParseInput input,
            int bannerAttr, int descriptionAttr, @Nullable Integer directBootAwareAttr,
            @Nullable Integer enabledAttr, int iconAttr, int labelAttr, int logoAttr, int nameAttr,
            @Nullable Integer processAttr, int roundIconAttr, @Nullable Integer splitNameAttr) {

......

        if(component.getName().equals("com.example.test.MainActivity")) {
            component.directBootAware = true;
            pkg.setPartiallyDirectBootAware(true);
        }

......

framework/ base/core/java/android/content/pm/parsing/ParsingPackageUtils.java解析package

    private void parseBaseAppBasicFlags(ParsingPackage pkg, TypedArray sa) {

......

        if (pkg.getPackageName().equals("com.example.test")) {
            pkg.setDirectBootAware(true);
        }

......

android 9则是在 

framework/base/core/java/android/content/pm/PackageParser.java解析package和组件的

    //解析package
    private boolean parseBaseApplication(Package owner, Resources res,
            XmlResourceParser parser, int flags, String[] outError)
        throws XmlPullParserException, IOException {

        ......


        if (sa.getBoolean(
                R.styleable.AndroidManifestApplication_defaultToDeviceProtectedStorage,
                false)) {
            ai.privateFlags |= ApplicationInfo.PRIVATE_FLAG_DEFAULT_TO_DEVICE_PROTECTED_STORAGE;
        }
        if (sa.getBoolean(
                R.styleable.AndroidManifestApplication_directBootAware,
                false)) {
            ai.privateFlags |= ApplicationInfo.PRIVATE_FLAG_DIRECT_BOOT_AWARE;
        }

        //add
        if (pkgName.equals("com.example.test")) {
            ai.privateFlags |= ApplicationInfo.PRIVATE_FLAG_DEFAULT_TO_DEVICE_PROTECTED_STORAGE;
            ai.privateFlags |= ApplicationInfo.PRIVATE_FLAG_DIRECT_BOOT_AWARE;
        }
        //end

        ......
    }



    //解析activity
    private Activity parseActivity(Package owner, Resources res,
            XmlResourceParser parser, int flags, String[] outError, CachedComponentArgs cachedArgs,
            boolean receiver, boolean hardwareAccelerated)
            throws XmlPullParserException, IOException {

        ......

        if (a.info.directBootAware) {
            owner.applicationInfo.privateFlags |=
                    ApplicationInfo.PRIVATE_FLAG_PARTIALLY_DIRECT_BOOT_AWARE;
        }

        //add
        if (a.info.name.equals("com.example.test.MainActivity")) {
            owner.applicationInfo.privateFlags |=
                    ApplicationInfo.PRIVATE_FLAG_PARTIALLY_DIRECT_BOOT_AWARE;
        }
        //end

        ......
    }

四. 遇到的问题

之前搞快速启动app的时候开了directBootAware模式,但启动的时候报如下错误

java.lang.IllegalStateException: SharedPreferences in credential encrypted storage are not available until after user is unlocked

......

android.database.sqlite.SQLiteCantOpenDatabaseException: unknown error (code 14 SQLITE_CANTOPEN): Could not open database

原因就是上面说的,没有Device Protected Storage权限

解决方案就是设置defaultToDeviceProtectedStorage为true

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值