关于AndroBench在Android 10以后性能衰减的问题分析

关于AndroBench在Android 10以后性能衰减的问题分析

背景

自Android 10发布以来,由于Google默认禁用了在Android P时引入的Compatibility WAL,加之AndroBench这一应用在代码层面存在于Android SQLite API不兼容的情况,导致Android 10以后的AndroBench SQLite部分跑分出现大幅下滑;

通过反编译AndroBench,我们得知,主要原因在于AndroBench没有使用Android framework API (enableWriteAheadLogging),而是使用raw语句来设置日志模式(PRAGMA journal_mode=wal),这导致Android framework无法获知日志模式发生改变,继而无法自动切换与之匹配的默认同步模式(PRAGMA synchronous)。

原生AOSP对于日志模式与同步模式的默认匹配如下:

WAL   - NORMAL
非WAL - FULL

默认由于默认禁用了Compatibility WAL,因此Android framework默认认为所有SQLite数据库的日志模式为DELETE(可在config.xml中修改db_default_journal_mode的值来改变这一默认日志模式),因此对应的同步模式为FULL

正常情况下,如果APP调用enableWriteAheadLogging来显式切换日志模式为WAL,Android framework会自动切换默认的同步模式;

而AndroBench是通过rawQuery进行参数传导,这导致Android framework API无法监测并及时修改默认的同步模式,从而使AndroBench在Android 10以上的版本中测试SQLite时使用WAL的日志模式,却在没有显式修改同步模式的情况下,没有使用默认的NORMAL同步模式;

分析步骤

1. 反编译AndroBench:

AndroBench没有使用混淆、加固等手段,因此使用d2j-dex2jar即可反编译;

定位到Testing_SQLite_DBHelper.java后发现,其在onConfigure回调中做了如下操作:

    public void onConfigure(final SQLiteDatabase sqLiteDatabase) {
        final Cursor rawQuery = sqLiteDatabase.rawQuery("PRAGMA journal_mode=" + this.journalMode, (String[])null);
        rawQuery.moveToNext();
        System.out.println("journal_mode=" + rawQuery.getString(0));
        rawQuery.close();
    }

这种情况下,Android framework只会将字符串直接下发给sqlite,而不会去判断其参数的分类,从而导致此时同步模式依旧为非WAL的默认值——FULL;

Q:为什么Android P版本此处是NORMAL?

A:因为在Android P上,Google引入了compatibility wal模式的默认支持,因此除非应用显示禁用WAL模式:

如下是Android P上通过日志模式确认同步模式的代码,Android 10上是类似的,就不分别列举了:

    private void setWalModeFromConfiguration() {
        if (!mConfiguration.isInMemoryDb() && !mIsReadOnlyConnection) {
            // 此处会在AndroBench通过rawQuery修改日志模式之前执行,并且由于其没有通过API调用,因此此处始终为false;
            final boolean walEnabled =
                    (mConfiguration.openFlags & SQLiteDatabase.ENABLE_WRITE_AHEAD_LOGGING) != 0;
            // Use compatibility WAL unless an app explicitly set journal/synchronous mode
            // or DISABLE_COMPATIBILITY_WAL flag is set
            // 此处Android P上默认为true,Android 10上默认为false
            final boolean useCompatibilityWal = mConfiguration.useCompatibilityWal();
            if (walEnabled || useCompatibilityWal) {
                //Android P走这里面
                setJournalMode("WAL");
                if (mConfiguration.syncMode != null) {
                    setSyncMode(mConfiguration.syncMode);
                } else if (useCompatibilityWal && SQLiteCompatibilityWalFlags.areFlagsSet()) {
                    setSyncMode(SQLiteCompatibilityWalFlags.getWALSyncMode());
                } else {
                    setSyncMode(SQLiteGlobal.getWALSyncMode());
                }
            } else {
                //Android 10走这里面
                setJournalMode(mConfiguration.journalMode == null
                        ? SQLiteGlobal.getDefaultJournalMode() : mConfiguration.journalMode);
                setSyncMode(mConfiguration.syncMode == null
                        ? SQLiteGlobal.getDefaultSyncMode() : mConfiguration.syncMode);
            }
        }
    }

2. 验证效果

如果上述分析正确,那么通过修改SQLiteGlobal.java中的getDefaultSyncMode()方法的参数,则可作用于AndroBench的同步模式;

以某SM7250平台手机(6GB + 128GB)为例,在user版本上进行验证:

(非正式版,此处仅用于展示改动前后的变化,具体数值在正式版上可能会有差异)

默认情况下:

Insert:   1822.90    1828.72    1896.34
Update:    2452.78    2499.33    2559.36
Delete:   2783.88    2760.58    2789.39

通过adb shell setprop debug.sqlite.syncmode NORMAL后:

Insert:   3100.91    3128.59    3045.44
Update:   3863.16    3956.29    3999.25
Delete:   4966.03    4933.55    4834.18

简单取平均值后对比发现,当WAL工作在NORMAL同步模式下时,AndroBench成绩较FULL同步模式分别提升:

           FULL       NORMAL     DIFF
Insert:   1849.32    3091.65    167%
Update:   2503.82    3939.57    157%
Delete:   2777.95    4911.25    176%

3. 改进措施

a. 通过在父类SQLiteOpenHelper的onConfigure回调之后进行判断,如果Android framework API检测到WAL没有启用(!db.isWriteAheadLoggingEnabled()),但实际通过rawQuery获取到的journal_mode确是WAL,此时认为App通过了rawQuery修改日志模式,此时显式调用一次enableWriteAheadLogging()即可;

b. 通过对SQL语句进行拦截,对PRAGMA journal_mode与PRAGMA synchronous两个参数的设置进行判断、绑定,使其与Android framework API的表现一致;

目前a方案已经开发完成,但是考虑到其可能存在部分特殊App功能发生改变:

如果存在某一应用,同时使用了PRAGMA journal_mode=wal,与PRAGMA synchronous=FULL(或OFF),方案a会覆盖其同步模式为NORMAL,这改变了App本身的逻辑,不符合修改的基本要求;

因此建议使用b方案实现;

  • 6
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值