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

Commit 2e090585 authored by Pawan Wagh's avatar Pawan Wagh Committed by Gerrit Code Review
Browse files

Merge "Wipe /data with ext4 before 16K OTA" into main

parents 12e45248 2951b024
Loading
Loading
Loading
Loading
+6 −0
Original line number Diff line number Diff line
@@ -11620,6 +11620,12 @@
    <!-- Toast message when 16k OTA update fails -->
    <string name="toast_16k_update_failed_text">Failed to update kernel to 16KB pages compatible kernel.</string>
    <string name="progress_16k_ota_title">Applying change</string>
    <!-- Confirmation dialog title and text to reformat data to ext4 -->
    <string name="confirm_format_ext4_title">Reformat device to ext4?</string>
    <string name="confirm_format_ext4_text">16K developer option is supported with ext4 filesystem. Device will be wiped and filesystem will be changed to ext4 after confirmation.</string>
    <!-- Toast on failure to reformat data to ext4 -->
    <string name="format_ext4_failure_toast">Failed to reformat and wipe the data partiton to ext4.</string>
    <!-- DSU Loader. Do not translate. -->
    <string name="dsu_loader_title" translatable="false">DSU Loader</string>
+67 −6
Original line number Diff line number Diff line
@@ -22,6 +22,7 @@ import android.os.Handler;
import android.os.ParcelFileDescriptor;
import android.os.PersistableBundle;
import android.os.PowerManager;
import android.os.RecoverySystem;
import android.os.SystemProperties;
import android.os.SystemUpdateManager;
import android.os.UpdateEngine;
@@ -34,7 +35,6 @@ import android.widget.ProgressBar;
import android.widget.Toast;

import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.annotation.VisibleForTesting;
import androidx.appcompat.app.AlertDialog;
import androidx.core.content.ContextCompat;
@@ -54,6 +54,7 @@ import com.google.common.util.concurrent.MoreExecutors;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
@@ -68,7 +69,8 @@ import java.util.zip.ZipFile;
public class Enable16kPagesPreferenceController extends DeveloperOptionsPreferenceController
        implements Preference.OnPreferenceChangeListener,
                PreferenceControllerMixin,
                Enable16kbPagesDialogHost {
                Enable16kbPagesDialogHost,
                EnableExt4DialogHost {

    private static final String TAG = "Enable16kPages";
    private static final String REBOOT_REASON = "toggle16k";
@@ -87,7 +89,7 @@ public class Enable16kPagesPreferenceController extends DeveloperOptionsPreferen
    private static final int OFFSET_TO_FILE_NAME = 30;
    public static final String EXPERIMENTAL_UPDATE_TITLE = "Android 16K Kernel Experimental Update";

    private @Nullable DevelopmentSettingsDashboardFragment mFragment = null;
    private @NonNull DevelopmentSettingsDashboardFragment mFragment;
    private boolean mEnable16k;

    private final ListeningExecutorService mExecutorService =
@@ -96,9 +98,9 @@ public class Enable16kPagesPreferenceController extends DeveloperOptionsPreferen
    private AlertDialog mProgressDialog;

    public Enable16kPagesPreferenceController(
            @NonNull Context context, @Nullable DevelopmentSettingsDashboardFragment fragment) {
            @NonNull Context context, @NonNull DevelopmentSettingsDashboardFragment fragment) {
        super(context);
        mFragment = fragment;
        this.mFragment = fragment;
    }

    @Override
@@ -114,6 +116,10 @@ public class Enable16kPagesPreferenceController extends DeveloperOptionsPreferen
    @Override
    public boolean onPreferenceChange(Preference preference, Object newValue) {
        mEnable16k = (Boolean) newValue;
        if (isDataf2fs()) {
            EnableExt4WarningDialog.show(mFragment, this);
            return false;
        }
        Enable16kPagesWarningDialog.show(mFragment, this, mEnable16k);
        return true;
    }
@@ -162,7 +168,7 @@ public class Enable16kPagesPreferenceController extends DeveloperOptionsPreferen
                    }

                    @Override
                    public void onFailure(Throwable t) {
                    public void onFailure(@NonNull Throwable t) {
                        hideProgressDialog();
                        Log.e(TAG, "Failed to call applyPayload of UpdateEngineStable!");
                        displayToast(mContext.getString(R.string.toast_16k_update_failed_text));
@@ -291,6 +297,41 @@ public class Enable16kPagesPreferenceController extends DeveloperOptionsPreferen
        Toast.makeText(mContext, message, Toast.LENGTH_SHORT).show();
    }

    @Override
    public void onExt4DialogConfirmed() {
        // user has confirmed to wipe the device
        ListenableFuture future = mExecutorService.submit(() -> wipeData());
        Futures.addCallback(
                future,
                new FutureCallback<>() {
                    @Override
                    public void onSuccess(@NonNull Object result) {
                        Log.i(TAG, "Wiping /data  with recovery system.");
                    }

                    @Override
                    public void onFailure(@NonNull Throwable t) {
                        Log.e(TAG, "Failed to change the /data partition with ext4");
                        displayToast(mContext.getString(R.string.format_ext4_failure_toast));
                    }
                },
                ContextCompat.getMainExecutor(mContext));
    }

    private void wipeData() {
        RecoverySystem recoveryService = mContext.getSystemService(RecoverySystem.class);
        try {
            recoveryService.wipePartitionToExt4();
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }

    @Override
    public void onExt4DialogDismissed() {
        // Do nothing
    }

    private class OtaUpdateCallback extends UpdateEngineStableCallback {
        UpdateEngineStable mUpdateEngineStable;

@@ -357,4 +398,24 @@ public class Enable16kPagesPreferenceController extends DeveloperOptionsPreferen
        infoBundle.putString(SystemUpdateManager.KEY_TITLE, EXPERIMENTAL_UPDATE_TITLE);
        return infoBundle;
    }

    private boolean isDataf2fs() {
        try (BufferedReader br = new BufferedReader(new FileReader("/proc/mounts"))) {
            String line;
            while ((line = br.readLine()) != null) {
                Log.i(TAG, line);
                final String[] fields = line.split(" ");
                final String partition = fields[1];
                final String fsType = fields[2];
                if (partition.equals("/data") && fsType.equals("f2fs")) {
                    return true;
                }
            }
        } catch (IOException e) {
            Log.e(TAG, "Failed to read /proc/mounts");
            displayToast(mContext.getString(R.string.format_ext4_failure_toast));
        }

        return false;
    }
}
+26 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2024 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.settings.development;

/** Interface for EnableExt4DialogHost callbacks. */
public interface EnableExt4DialogHost {
    /** Callback when the user presses ok the warning dialog. */
    void onExt4DialogConfirmed();

    /** Callback when the user cancels or dismisses the warning dialog. */
    void onExt4DialogDismissed();
}
+93 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2024 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.settings.development;

import android.app.Dialog;
import android.app.settings.SettingsEnums;
import android.content.DialogInterface;
import android.os.Bundle;

import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.appcompat.app.AlertDialog;
import androidx.fragment.app.Fragment;
import androidx.fragment.app.FragmentManager;

import com.android.internal.annotations.Initializer;
import com.android.settings.R;
import com.android.settings.core.instrumentation.InstrumentedDialogFragment;

/** Dialog when user interacts 16K pages developer option and data is f2fs */
public class EnableExt4WarningDialog extends InstrumentedDialogFragment
        implements DialogInterface.OnClickListener, DialogInterface.OnDismissListener {

    public static final String TAG = "EnableExt4WarningDialog";

    private EnableExt4DialogHost mHost;

    @Initializer
    private void setHost(@NonNull EnableExt4DialogHost host) {
        this.mHost = host;
    }

    /** This method is used to show warning dialog to reformat data to /ext4 */
    public static void show(
            @NonNull Fragment hostFragment, @NonNull EnableExt4DialogHost dialogHost) {
        final FragmentManager manager = hostFragment.getActivity().getSupportFragmentManager();
        Fragment existingFragment = manager.findFragmentByTag(TAG);
        if (existingFragment == null) {
            existingFragment = new EnableExt4WarningDialog();
        }

        if (existingFragment instanceof EnableExt4WarningDialog) {
            existingFragment.setTargetFragment(hostFragment, 0 /* requestCode */);
            ((EnableExt4WarningDialog) existingFragment).setHost(dialogHost);
            ((EnableExt4WarningDialog) existingFragment).show(manager, TAG);
        }
    }

    @Override
    public int getMetricsCategory() {
        return SettingsEnums.DIALOG_ENABLE_16K_PAGES;
    }

    @NonNull
    @Override
    public Dialog onCreateDialog(@Nullable Bundle savedInstanceState) {
        return new AlertDialog.Builder(getActivity())
                .setTitle(R.string.confirm_format_ext4_title)
                .setMessage(R.string.confirm_format_ext4_text)
                .setPositiveButton(android.R.string.ok, this /* onClickListener */)
                .setNegativeButton(android.R.string.cancel, this /* onClickListener */)
                .create();
    }

    @Override
    public void onClick(@NonNull DialogInterface dialog, int buttonId) {
        if (buttonId == DialogInterface.BUTTON_POSITIVE) {
            mHost.onExt4DialogConfirmed();
        } else {
            mHost.onExt4DialogDismissed();
        }
    }

    @Override
    public void onDismiss(@NonNull DialogInterface dialog) {
        super.onDismiss(dialog);
        mHost.onExt4DialogDismissed();
    }
}