zram writeback 代码分析

目录

正文

zram writeback开关

JobScheduler的API介绍

ZramWriteback的实现


正文

zram writeback开关

将settings的值存储到属性中,然后再执行zram writeback的schedule,正常情况下属性值是1和0这两种,如果没有值的话,则表示没有打开。

frameworks/base/core/java/android/provider/Settings.java

        public static final String ZRAM_ENABLED =
                "zram_enabled";

frameworks/base/services/core/java/com/android/server/StorageManagerService.java

    /* Read during boot to decide whether to enable zram when available */
    private static final String ZRAM_ENABLED_PROPERTY =
            "persist.sys.zram_enabled";

    // storage service起来之后,首先执行的动作
    private void handleSystemReady() {

        // 监听Settings的ZRAM_ENABLED,如果发生变动,则触发refreshZramSettings()
        mContext.getContentResolver().registerContentObserver(
            Settings.Global.getUriFor(Settings.Global.ZRAM_ENABLED),
            false /*notifyForDescendants*/,
            new ContentObserver(null /* current thread */) {
                @Override
                public void onChange(boolean selfChange) {
                    refreshZramSettings();
                }
            });
        refreshZramSettings();

        // persist.sys.zram_enabled 判断是否为非0,并且config_zramWriteback设置为true
        // 则进行writeback的job的调度
        String zramPropValue = SystemProperties.get(ZRAM_ENABLED_PROPERTY);
        if (!zramPropValue.equals("0")
                && mContext.getResources().getBoolean(
                    com.android.internal.R.bool.config_zramWriteback)) {
            ZramWriteback.scheduleZramWriteback(mContext);
        }
    }


    private void refreshZramSettings() {
        String propertyValue = SystemProperties.get(ZRAM_ENABLED_PROPERTY);
        if ("".equals(propertyValue)) {
            return;  // System doesn't have zram toggling support
        }
        String desiredPropertyValue =
            Settings.Global.getInt(mContext.getContentResolver(),
                                   Settings.Global.ZRAM_ENABLED,
                                   1) != 0
            ? "1" : "0";
        // 如果属性值跟settings里面的值不相等,则更新属性里面的值
        if (!desiredPropertyValue.equals(propertyValue)) {
            SystemProperties.set(ZRAM_ENABLED_PROPERTY, desiredPropertyValue);
            // 如果settings里面的值是1,则进行调度。
            if (desiredPropertyValue.equals("1")
                    && mContext.getResources().getBoolean(
                        com.android.internal.R.bool.config_zramWriteback)) {
                ZramWriteback.scheduleZramWriteback(mContext);
            }
        }
    }

JobScheduler的API介绍

public class JobSchedulerService extends JobService{
  @Overrid
  public boolean onStartJob(JobParameters params){
    return false;
  }

  @Override
  public boolean onStopJob(JobParameters params){
    return false;
  }
}

onStartJob
当系统要触发执行我们的Job的时候,会调用onStartJob方法。这个方法会返回一个布尔型的值。

当返回false的时候,系统会认为onStartJob这个方法返回的时候,我们要做的工作已经做完了,这不是一个耗时的工作。

当返回true的时候,系统会认为我们要执行一个耗时的工作,在onStartJob这个方法返回的时候,我们的工作仍然在异步执行。当我们的工作执行完成的时候,我们必须手动调用jobFinished(JobParameters params, boolean needRescheduled)

务必要注意,如果onStartJob返回了true,在异步工作执行完成之后,我们必须手动调用jobFinished方法,如果不调用jobFinished,系统会一直认为我们在执行当前Job,那么系统就不会再入队其他的Job去执行,也就是说JobScheduler的执行队列就会被阻塞了

onStopJob
当系统收到一个cancel job的请求时,并且这个job仍然在执行,系统就会调用onStopJob方法。

也就是说在系统收到取消请求时,并不会一定会调用onStopJob方法,只有onStartJob返回true的时候,才会调用onStopJob,否则不调用。
但不论是否调用onStopJob方法,系统受到取消请求时,都会取消该job。

JobSchedulerService在cancel一个Job的大体思路是:

1. 将Job从PendingJobs中移除,这个PendingJob包含了达到触发条件但还没有执行的Job
2. 如果在cancel的时候该Job正在被执行,则最终会调用到我们App的onStopJob方法。如果已经执行完了,则不会调用onStopJob方法。

需要注意的是,JobService是运行在我们应用的主线程,这意味着我们需要开启新线程或者使用Handler或者AsyncTask来处理耗时的工作。

这部分主要参考Android JobScheduler的使用和原理 - 简书 (jianshu.com)

ZramWriteback的实现

首先是从StorageServiceManager那边调用过来的,会触发两次的schedule行为,第一次是markPageAsIdle(),第二次则writeback的行为,这次writeback要求是20分钟之后,3小时以内一定会执行一次writeback的操作,这两个具体逻辑实现都在onStartJob里面。并且执行完第一次writeback之后,将会触发下一次的schedule的操作,是要求24小时之后,并且需要设备进入idle 71分钟。

frameworks/base/services/core/java/com/android/server/ZramWriteback.java
    private static final ComponentName sZramWriteback =
            new ComponentName("android", ZramWriteback.class.getName());
    private static final int MARK_IDLE_JOB_ID = 811;
    private static final int WRITEBACK_IDLE_JOB_ID = 812;
    private static final String MARK_IDLE_DELAY_PROP = "ro.zram.mark_idle_delay_mins";
    private static final String FIRST_WB_DELAY_PROP = "ro.zram.first_wb_delay_mins";
    private static final String PERIODIC_WB_DELAY_PROP = "ro.zram.periodic_wb_delay_hours";
    private static final String FORCE_WRITEBACK_PROP = "zram.force_writeback";

    /**
     * 从StorageServiceManager调用过来的,
     * Schedule the zram writeback job to trigger a writeback when idle
     */
    public static void scheduleZramWriteback(Context context) {
        int markIdleDelay = SystemProperties.getInt(MARK_IDLE_DELAY_PROP, 20);
        int firstWbDelay = SystemProperties.getInt(FIRST_WB_DELAY_PROP, 180);
        boolean forceWb = SystemProperties.getBoolean(FORCE_WRITEBACK_PROP, false);

        JobScheduler js = (JobScheduler) context.getSystemService(Context.JOB_SCHEDULER_SERVICE);

        // 触发一个job,至少20分钟之后执行,在3小时的时候准时执行,忽略其他条件,将文件设置为idle状态
        js.schedule(new JobInfo.Builder(MARK_IDLE_JOB_ID, sZramWriteback)
                        .setMinimumLatency(TimeUnit.MINUTES.toMillis(markIdleDelay))
                        .setOverrideDeadline(TimeUnit.MINUTES.toMillis(markIdleDelay))
                        .build());

        // 第一次的schedule,是在3小时之后,并且要求设备进入idle状态,即设备处于屏幕关闭或dreaming状态(类似window的休眠动画状态)71分钟后。
        js.schedule(new JobInfo.Builder(WRITEBACK_IDLE_JOB_ID, sZramWriteback)
                        .setMinimumLatency(TimeUnit.MINUTES.toMillis(firstWbDelay))
                        .setRequiresDeviceIdle(!forceWb)
                        .build());
    }

接下来看看onStartJob的行为:

    @Override
    public boolean onStartJob(JobParameters params) {

        if (!isWritebackEnabled()) {
            jobFinished(params, false);
            return false;
        }

        if (params.getJobId() == MARK_IDLE_JOB_ID) {
            markPagesAsIdle();
            
            jobFinished(params, false);
            return false;
        } else {
            new Thread("ZramWriteback_WritebackIdlePages") {
                @Override
                public void run() {
                    markAndFlushPages();
                    // 出发下一次的调度行为
                    schedNextWriteback(ZramWriteback.this);
                    // 表示这个job已经完成了,无需进行重新调度
                    jobFinished(params, false);
                }
            }.start();
        }
        return true;
    }

    private static final String IDLE_SYS = "/sys/block/zram%d/idle";
    private static int sZramDeviceId = 0;
    private static final String IDLE_SYS_ALL_PAGES = "all";

    // 往/sys/block/zram0/idle 写入 all
    private void markPagesAsIdle() {
        String idlePath = String.format(IDLE_SYS, sZramDeviceId);
        try {
            FileUtils.stringToFile(new File(idlePath), IDLE_SYS_ALL_PAGES);
        } catch (IOException e) {
            Slog.e(TAG, "Failed to write to " + idlePath);
        }
    }

    private static final String WB_SYS = "/sys/block/zram%d/writeback";
    private static final String WB_SYS_IDLE_PAGES = "idle";

    // 往 /sys/block/zram0/writeback 写入 idle
    private void flushIdlePages() {
        String wbPath = String.format(WB_SYS, sZramDeviceId);
        try {
            FileUtils.stringToFile(new File(wbPath), WB_SYS_IDLE_PAGES);
        } catch (IOException e) {
            Slog.e(TAG, "Failed to write to " + wbPath);
        }
        if (DEBUG) Slog.d(TAG, "Finished writeback back idle pages");
    }


    private void markAndFlushPages() {
        // 往 /sys/block/zram0/writeback 写入 idle
        flushIdlePages();
        // 往/sys/block/zram0/idle 写入 all
        markPagesAsIdle();

        }
    }

    private static final String PERIODIC_WB_DELAY_PROP = "ro.zram.periodic_wb_delay_hours";

    private static void schedNextWriteback(Context context) {
        int nextWbDelay = SystemProperties.getInt(PERIODIC_WB_DELAY_PROP, 24);
        boolean forceWb = SystemProperties.getBoolean(FORCE_WRITEBACK_PROP, false);
        JobScheduler js = (JobScheduler) context.getSystemService(Context.JOB_SCHEDULER_SERVICE);
        // 延时24小时之后,并且设备进入idle 71分钟会触发writeback的行为
        js.schedule(new JobInfo.Builder(WRITEBACK_IDLE_JOB_ID, sZramWriteback)
                        .setMinimumLatency(TimeUnit.HOURS.toMillis(nextWbDelay))
                        .setRequiresDeviceIdle(!forceWb)
                        .build());
    }

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值