Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 7265abe7 authored by Christopher Tate's avatar Christopher Tate Committed by Dianne Hackborn
Browse files

Be increasingly aggressive about fstrim if it isn't being run

The current heuristics depend on devices being alive at midnight+ in
order to run periodic background fstrim operations.  This unfortunately
means that people who routinely turn their devices off overnight wind
up with their devices *never* running fstrim, and this causes major
performance and disk-life problems.

We now backstop this very-friendly schedule with an increasingly
aggressive one.  If the device goes a defined time without a background
fstrim, we then force the fstrim at the next reboot.  Once the
device hits the midnight+ idle fstrim request time, then we already
aggressively attempt to fstrim at the first available moment
thereafter, even if it's days/weeks later without a reboot.

'Available' here means charging + device idle.  If the device never
becomes idle then we can't do much without rendering an in-use device
inoperable for some number of minutes -- but we have no evidence of
devices ever failing to run fstrim due to this usage pattern.

A new Settings.Global element (type 'long', called
"fstrim_mandatory_interval") is the source of the backstop time.  If
this element is zero or negative, no mandatory boot-time fstrim will
ever be performed.  If the element is not supplied on a given device,
the default backstop is 3 days.

Adds a new string to display in the upgrading dialog when doing
the fstrim.  Note it is too late for this to be localized, but since
this operation can take a long time it is probably better to have
it show *something* even if not localized, rather than just sit there.

Bug 18486922

Change-Id: I5b265ca0a65570fb8931251aa1ac37b530635a2c
parent 1586b9c3
Loading
Loading
Loading
Loading
+63 −0
Original line number Diff line number Diff line
@@ -856,6 +856,38 @@ public interface IMountService extends IInterface {
                }
                return _result;
            }

            @Override
            public long lastMaintenance() throws RemoteException {
                Parcel _data = Parcel.obtain();
                Parcel _reply = Parcel.obtain();
                long _result;
                try {
                    _data.writeInterfaceToken(DESCRIPTOR);
                    mRemote.transact(Stub.TRANSACTION_lastMaintenance, _data, _reply, 0);
                    _reply.readException();
                    _result = _reply.readLong();
                } finally {
                    _reply.recycle();
                    _data.recycle();
                }
                return _result;
            }

            @Override
            public void runMaintenance() throws RemoteException {
                Parcel _data = Parcel.obtain();
                Parcel _reply = Parcel.obtain();
                try {
                    _data.writeInterfaceToken(DESCRIPTOR);
                    mRemote.transact(Stub.TRANSACTION_runMaintenance, _data, _reply, 0);
                    _reply.readException();
                } finally {
                    _reply.recycle();
                    _data.recycle();
                }
                return;
            }
        }

        private static final String DESCRIPTOR = "IMountService";
@@ -942,6 +974,10 @@ public interface IMountService extends IInterface {

        static final int TRANSACTION_resizeSecureContainer = IBinder.FIRST_CALL_TRANSACTION + 40;

        static final int TRANSACTION_lastMaintenance = IBinder.FIRST_CALL_TRANSACTION + 41;

        static final int TRANSACTION_runMaintenance = IBinder.FIRST_CALL_TRANSACTION + 42;

        /**
         * Cast an IBinder object into an IMountService interface, generating a
         * proxy if needed.
@@ -1347,6 +1383,19 @@ public interface IMountService extends IInterface {
                    reply.writeInt(resultCode);
                    return true;
                }
                case TRANSACTION_lastMaintenance: {
                    data.enforceInterface(DESCRIPTOR);
                    long lastMaintenance = lastMaintenance();
                    reply.writeNoException();
                    reply.writeLong(lastMaintenance);
                    return true;
                }
                case TRANSACTION_runMaintenance: {
                    data.enforceInterface(DESCRIPTOR);
                    runMaintenance();
                    reply.writeNoException();
                    return true;
                }
            }
            return super.onTransact(code, data, reply, flags);
        }
@@ -1617,4 +1666,18 @@ public interface IMountService extends IInterface {
    public String getField(String field) throws RemoteException;

    public int resizeSecureContainer(String id, int sizeMb, String key) throws RemoteException;

    /**
     * Report the time of the last maintenance operation such as fstrim.
     * @return Timestamp of the last maintenance operation, in the
     *     System.currentTimeMillis() time base
     * @throws RemoteException
     */
    public long lastMaintenance() throws RemoteException;

    /**
     * Kick off an immediate maintenance operation
     * @throws RemoteException
     */
    public void runMaintenance() throws RemoteException;
}
+7 −0
Original line number Diff line number Diff line
@@ -5543,6 +5543,13 @@ public final class Settings {
        */
       public static final String PACKAGE_VERIFIER_INCLUDE_ADB = "verifier_verify_adb_installs";

       /**
        * Time since last fstrim (milliseconds) after which we force one to happen
        * during device startup.  If unset, the default is 3 days.
        * @hide
        */
       public static final String FSTRIM_MANDATORY_INTERVAL = "fstrim_mandatory_interval";

       /**
        * The interval in milliseconds at which to check packet counts on the
        * mobile data interface when screen is on, to detect possible data
+3 −0
Original line number Diff line number Diff line
@@ -3508,6 +3508,9 @@
    <!-- [CHAR LIMIT=40] Title of dialog that is shown when performing a system upgrade. -->
    <string name="android_upgrading_title">Android is upgrading\u2026</string>

    <!-- [CHAR LIMIT=NONE] Message shown in upgrading dialog when doing an fstrim. -->
    <string name="android_upgrading_fstrim">Optimizing storage.</string>

    <!-- [CHAR LIMIT=NONE] Message shown in upgrading dialog for each .apk that is optimized. -->
    <string name="android_upgrading_apk">Optimizing app
        <xliff:g id="number" example="123">%1$d</xliff:g> of
+1 −0
Original line number Diff line number Diff line
@@ -1644,6 +1644,7 @@
  <java-symbol type="string" name="aerr_application" />
  <java-symbol type="string" name="aerr_process" />
  <java-symbol type="string" name="aerr_title" />
  <java-symbol type="string" name="android_upgrading_fstrim" />
  <java-symbol type="string" name="android_upgrading_apk" />
  <java-symbol type="string" name="android_upgrading_complete" />
  <java-symbol type="string" name="android_upgrading_starting_apps" />
+52 −0
Original line number Diff line number Diff line
@@ -83,6 +83,7 @@ import org.xmlpull.v1.XmlPullParserException;

import java.io.File;
import java.io.FileDescriptor;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.PrintWriter;
import java.math.BigInteger;
@@ -90,7 +91,9 @@ import java.nio.charset.StandardCharsets;
import java.security.NoSuchAlgorithmException;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.KeySpec;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
@@ -359,6 +362,11 @@ class MountService extends IMountService.Stub
    // Used in the ObbActionHandler
    private IMediaContainerService mContainerService = null;

    // Last fstrim operation tracking
    private static final String LAST_FSTRIM_FILE = "last-fstrim";
    private final File mLastMaintenanceFile;
    private long mLastMaintenance;

    // Handler messages
    private static final int H_UNMOUNT_PM_UPDATE = 1;
    private static final int H_UNMOUNT_PM_DONE = 2;
@@ -536,6 +544,15 @@ class MountService extends IMountService.Stub
                case H_FSTRIM: {
                    waitForReady();
                    Slog.i(TAG, "Running fstrim idle maintenance");

                    // Remember when we kicked it off
                    try {
                        mLastMaintenance = System.currentTimeMillis();
                        mLastMaintenanceFile.setLastModified(mLastMaintenance);
                    } catch (Exception e) {
                        Slog.e(TAG, "Unable to record last fstrim!");
                    }

                    try {
                        // This method must be run on the main (handler) thread,
                        // so it is safe to directly call into vold.
@@ -544,6 +561,7 @@ class MountService extends IMountService.Stub
                    } catch (NativeDaemonConnectorException ndce) {
                        Slog.e(TAG, "Failed to run fstrim!");
                    }

                    // invoke the completion callback, if any
                    Runnable callback = (Runnable) msg.obj;
                    if (callback != null) {
@@ -699,6 +717,18 @@ class MountService extends IMountService.Stub
        mHandler.sendMessage(mHandler.obtainMessage(H_FSTRIM, callback));
    }

    // Binder entry point for kicking off an immediate fstrim
    @Override
    public void runMaintenance() {
        validatePermission(android.Manifest.permission.MOUNT_UNMOUNT_FILESYSTEMS);
        runIdleMaintenance(null);
    }

    @Override
    public long lastMaintenance() {
        return mLastMaintenance;
    }

    private void doShareUnshareVolume(String path, String method, boolean enable) {
        // TODO: Add support for multiple share methods
        if (!method.equals("ums")) {
@@ -1477,6 +1507,22 @@ class MountService extends IMountService.Stub
        // Add OBB Action Handler to MountService thread.
        mObbActionHandler = new ObbActionHandler(IoThread.get().getLooper());

        // Initialize the last-fstrim tracking if necessary
        File dataDir = Environment.getDataDirectory();
        File systemDir = new File(dataDir, "system");
        mLastMaintenanceFile = new File(systemDir, LAST_FSTRIM_FILE);
        if (!mLastMaintenanceFile.exists()) {
            // Not setting mLastMaintenance here means that we will force an
            // fstrim during reboot following the OTA that installs this code.
            try {
                (new FileOutputStream(mLastMaintenanceFile)).close();
            } catch (IOException e) {
                Slog.e(TAG, "Unable to create fstrim record " + mLastMaintenanceFile.getPath());
            }
        } else {
            mLastMaintenance = mLastMaintenanceFile.lastModified();
        }

        /*
         * Create the connection to vold with a maximum queue of twice the
         * amount of containers we'd ever expect to have. This keeps an
@@ -3075,6 +3121,12 @@ class MountService extends IMountService.Stub
        pw.increaseIndent();
        mConnector.dump(fd, pw, args);
        pw.decreaseIndent();

        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");

        pw.println();
        pw.print("Last maintenance: ");
        pw.println(sdf.format(new Date(mLastMaintenance)));
    }

    /** {@inheritDoc} */
Loading