Loading core/res/AndroidManifest.xml +5 −0 Original line number Diff line number Diff line Loading @@ -4764,6 +4764,11 @@ android:permission="android.permission.BIND_JOB_SERVICE" > </service> <service android:name="com.android.server.ZramWriteback" android:exported="false" android:permission="android.permission.BIND_JOB_SERVICE" > </service> <service android:name="com.android.server.backup.FullBackupJob" android:exported="true" android:permission="android.permission.BIND_JOB_SERVICE" > Loading core/res/res/values/config.xml +3 −0 Original line number Diff line number Diff line Loading @@ -3735,4 +3735,7 @@ <!-- If the sensor that silences alerts is available or not. --> <bool name="config_silenceSensorAvailable">false</bool> <!-- Enable Zram writeback feature to allow unused pages in zram be written to flash. --> <bool name="config_zramWriteback">false</bool> </resources> core/res/res/values/symbols.xml +2 −0 Original line number Diff line number Diff line Loading @@ -3543,4 +3543,6 @@ <java-symbol type="bool" name="config_skipSensorAvailable" /> <java-symbol type="bool" name="config_silenceSensorAvailable" /> <java-symbol type="bool" name="config_zramWriteback" /> </resources> services/core/java/com/android/server/StorageManagerService.java +13 −0 Original line number Diff line number Diff line Loading @@ -780,6 +780,13 @@ class StorageManagerService extends IStorageManager.Stub }); refreshZramSettings(); // Schedule zram writeback unless zram is disabled by persist.sys.zram_enabled String zramPropValue = SystemProperties.get(ZRAM_ENABLED_PROPERTY); if (!zramPropValue.equals("0") && mContext.getResources().getBoolean( com.android.internal.R.bool.config_zramWriteback)) { ZramWriteback.scheduleZramWriteback(mContext); } // Toggle isolated-enable system property in response to settings mContext.getContentResolver().registerContentObserver( Settings.Global.getUriFor(Settings.Global.ISOLATED_STORAGE_REMOTE), Loading Loading @@ -813,6 +820,12 @@ class StorageManagerService extends IStorageManager.Stub // changing the property value. There's no race: we're the // sole writer. SystemProperties.set(ZRAM_ENABLED_PROPERTY, desiredPropertyValue); // Schedule writeback only if zram is being enabled. if (desiredPropertyValue.equals("1") && mContext.getResources().getBoolean( com.android.internal.R.bool.config_zramWriteback)) { ZramWriteback.scheduleZramWriteback(mContext); } } } Loading services/core/java/com/android/server/ZramWriteback.java 0 → 100644 +187 −0 Original line number Diff line number Diff line /* * Copyright (C) 2019 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.android.server; import android.app.job.JobInfo; import android.app.job.JobParameters; import android.app.job.JobScheduler; import android.app.job.JobService; import android.content.ComponentName; import android.content.Context; import android.os.FileUtils; import android.os.SystemProperties; import android.util.Slog; import java.io.File; import java.io.IOException; import java.util.concurrent.TimeUnit; /** * Schedules jobs for triggering zram writeback. */ public final class ZramWriteback extends JobService { private static final String TAG = "ZramWriteback"; private static final boolean DEBUG = false; 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 int MAX_ZRAM_DEVICES = 256; private static int sZramDeviceId = 0; private static final String IDLE_SYS = "/sys/block/zram%d/idle"; private static final String IDLE_SYS_ALL_PAGES = "all"; private static final String WB_SYS = "/sys/block/zram%d/writeback"; private static final String WB_SYS_IDLE_PAGES = "idle"; private static final String WB_STATS_SYS = "/sys/block/zram%d/bd_stat"; private static final int WB_STATS_MAX_FILE_SIZE = 128; private static final String BDEV_SYS = "/sys/block/zram%d/backing_dev"; 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 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 void flushIdlePages() { if (DEBUG) Slog.d(TAG, "Start writing back idle pages to disk"); 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 int getWrittenPageCount() { String wbStatsPath = String.format(WB_STATS_SYS, sZramDeviceId); try { String wbStats = FileUtils .readTextFile(new File(wbStatsPath), WB_STATS_MAX_FILE_SIZE, ""); return Integer.parseInt(wbStats.trim().split("\\s+")[2], 10); } catch (IOException e) { Slog.e(TAG, "Failed to read writeback stats from " + wbStatsPath); } return -1; } private void markAndFlushPages() { int pageCount = getWrittenPageCount(); flushIdlePages(); markPagesAsIdle(); if (pageCount != -1) { Slog.i(TAG, "Total pages written to disk is " + (getWrittenPageCount() - pageCount)); } } private static boolean isWritebackEnabled() { try { String backingDev = FileUtils .readTextFile(new File(String.format(BDEV_SYS, sZramDeviceId)), 128, ""); if (!"none".equals(backingDev.trim())) { return true; } else { Slog.w(TAG, "Writeback device is not set"); } } catch (IOException e) { Slog.w(TAG, "Writeback is not enabled on zram"); } return false; } private static void schedNextWriteback(Context context) { int nextWbDelay = SystemProperties.getInt(PERIODIC_WB_DELAY_PROP, 24); JobScheduler js = (JobScheduler) context.getSystemService(Context.JOB_SCHEDULER_SERVICE); js.schedule(new JobInfo.Builder(WRITEBACK_IDLE_JOB_ID, sZramWriteback) .setMinimumLatency(TimeUnit.HOURS.toMillis(nextWbDelay)) .setRequiresDeviceIdle(true) .build()); } @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); jobFinished(params, false); } }.start(); } return true; } @Override public boolean onStopJob(JobParameters params) { // The thread that triggers the writeback is non-interruptible return false; } /** * 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); JobScheduler js = (JobScheduler) context.getSystemService(Context.JOB_SCHEDULER_SERVICE); // Schedule a one time job to mark pages as idle. These pages will be written // back at later point if they remain untouched. js.schedule(new JobInfo.Builder(MARK_IDLE_JOB_ID, sZramWriteback) .setMinimumLatency(TimeUnit.MINUTES.toMillis(markIdleDelay)) .build()); // Schedule a one time job to flush idle pages to disk. // After the initial writeback, subsequent writebacks are done at interval set // by ro.zram.periodic_wb_delay_hours. js.schedule(new JobInfo.Builder(WRITEBACK_IDLE_JOB_ID, sZramWriteback) .setMinimumLatency(TimeUnit.MINUTES.toMillis(firstWbDelay)) .setRequiresDeviceIdle(true) .build()); } } Loading
core/res/AndroidManifest.xml +5 −0 Original line number Diff line number Diff line Loading @@ -4764,6 +4764,11 @@ android:permission="android.permission.BIND_JOB_SERVICE" > </service> <service android:name="com.android.server.ZramWriteback" android:exported="false" android:permission="android.permission.BIND_JOB_SERVICE" > </service> <service android:name="com.android.server.backup.FullBackupJob" android:exported="true" android:permission="android.permission.BIND_JOB_SERVICE" > Loading
core/res/res/values/config.xml +3 −0 Original line number Diff line number Diff line Loading @@ -3735,4 +3735,7 @@ <!-- If the sensor that silences alerts is available or not. --> <bool name="config_silenceSensorAvailable">false</bool> <!-- Enable Zram writeback feature to allow unused pages in zram be written to flash. --> <bool name="config_zramWriteback">false</bool> </resources>
core/res/res/values/symbols.xml +2 −0 Original line number Diff line number Diff line Loading @@ -3543,4 +3543,6 @@ <java-symbol type="bool" name="config_skipSensorAvailable" /> <java-symbol type="bool" name="config_silenceSensorAvailable" /> <java-symbol type="bool" name="config_zramWriteback" /> </resources>
services/core/java/com/android/server/StorageManagerService.java +13 −0 Original line number Diff line number Diff line Loading @@ -780,6 +780,13 @@ class StorageManagerService extends IStorageManager.Stub }); refreshZramSettings(); // Schedule zram writeback unless zram is disabled by persist.sys.zram_enabled String zramPropValue = SystemProperties.get(ZRAM_ENABLED_PROPERTY); if (!zramPropValue.equals("0") && mContext.getResources().getBoolean( com.android.internal.R.bool.config_zramWriteback)) { ZramWriteback.scheduleZramWriteback(mContext); } // Toggle isolated-enable system property in response to settings mContext.getContentResolver().registerContentObserver( Settings.Global.getUriFor(Settings.Global.ISOLATED_STORAGE_REMOTE), Loading Loading @@ -813,6 +820,12 @@ class StorageManagerService extends IStorageManager.Stub // changing the property value. There's no race: we're the // sole writer. SystemProperties.set(ZRAM_ENABLED_PROPERTY, desiredPropertyValue); // Schedule writeback only if zram is being enabled. if (desiredPropertyValue.equals("1") && mContext.getResources().getBoolean( com.android.internal.R.bool.config_zramWriteback)) { ZramWriteback.scheduleZramWriteback(mContext); } } } Loading
services/core/java/com/android/server/ZramWriteback.java 0 → 100644 +187 −0 Original line number Diff line number Diff line /* * Copyright (C) 2019 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.android.server; import android.app.job.JobInfo; import android.app.job.JobParameters; import android.app.job.JobScheduler; import android.app.job.JobService; import android.content.ComponentName; import android.content.Context; import android.os.FileUtils; import android.os.SystemProperties; import android.util.Slog; import java.io.File; import java.io.IOException; import java.util.concurrent.TimeUnit; /** * Schedules jobs for triggering zram writeback. */ public final class ZramWriteback extends JobService { private static final String TAG = "ZramWriteback"; private static final boolean DEBUG = false; 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 int MAX_ZRAM_DEVICES = 256; private static int sZramDeviceId = 0; private static final String IDLE_SYS = "/sys/block/zram%d/idle"; private static final String IDLE_SYS_ALL_PAGES = "all"; private static final String WB_SYS = "/sys/block/zram%d/writeback"; private static final String WB_SYS_IDLE_PAGES = "idle"; private static final String WB_STATS_SYS = "/sys/block/zram%d/bd_stat"; private static final int WB_STATS_MAX_FILE_SIZE = 128; private static final String BDEV_SYS = "/sys/block/zram%d/backing_dev"; 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 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 void flushIdlePages() { if (DEBUG) Slog.d(TAG, "Start writing back idle pages to disk"); 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 int getWrittenPageCount() { String wbStatsPath = String.format(WB_STATS_SYS, sZramDeviceId); try { String wbStats = FileUtils .readTextFile(new File(wbStatsPath), WB_STATS_MAX_FILE_SIZE, ""); return Integer.parseInt(wbStats.trim().split("\\s+")[2], 10); } catch (IOException e) { Slog.e(TAG, "Failed to read writeback stats from " + wbStatsPath); } return -1; } private void markAndFlushPages() { int pageCount = getWrittenPageCount(); flushIdlePages(); markPagesAsIdle(); if (pageCount != -1) { Slog.i(TAG, "Total pages written to disk is " + (getWrittenPageCount() - pageCount)); } } private static boolean isWritebackEnabled() { try { String backingDev = FileUtils .readTextFile(new File(String.format(BDEV_SYS, sZramDeviceId)), 128, ""); if (!"none".equals(backingDev.trim())) { return true; } else { Slog.w(TAG, "Writeback device is not set"); } } catch (IOException e) { Slog.w(TAG, "Writeback is not enabled on zram"); } return false; } private static void schedNextWriteback(Context context) { int nextWbDelay = SystemProperties.getInt(PERIODIC_WB_DELAY_PROP, 24); JobScheduler js = (JobScheduler) context.getSystemService(Context.JOB_SCHEDULER_SERVICE); js.schedule(new JobInfo.Builder(WRITEBACK_IDLE_JOB_ID, sZramWriteback) .setMinimumLatency(TimeUnit.HOURS.toMillis(nextWbDelay)) .setRequiresDeviceIdle(true) .build()); } @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); jobFinished(params, false); } }.start(); } return true; } @Override public boolean onStopJob(JobParameters params) { // The thread that triggers the writeback is non-interruptible return false; } /** * 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); JobScheduler js = (JobScheduler) context.getSystemService(Context.JOB_SCHEDULER_SERVICE); // Schedule a one time job to mark pages as idle. These pages will be written // back at later point if they remain untouched. js.schedule(new JobInfo.Builder(MARK_IDLE_JOB_ID, sZramWriteback) .setMinimumLatency(TimeUnit.MINUTES.toMillis(markIdleDelay)) .build()); // Schedule a one time job to flush idle pages to disk. // After the initial writeback, subsequent writebacks are done at interval set // by ro.zram.periodic_wb_delay_hours. js.schedule(new JobInfo.Builder(WRITEBACK_IDLE_JOB_ID, sZramWriteback) .setMinimumLatency(TimeUnit.MINUTES.toMillis(firstWbDelay)) .setRequiresDeviceIdle(true) .build()); } }