diff options
author | Pawan Wagh <waghpawan@google.com> | 2024-02-23 01:04:29 +0000 |
---|---|---|
committer | Pawan Wagh <waghpawan@google.com> | 2024-03-08 03:12:40 +0000 |
commit | 2951b024dc4e741125631469d457d89d4bc0a359 (patch) | |
tree | a66770db3f6e3a37c8f54db4d30bc52583a37632 | |
parent | ff6f53b24a9fa19ed75304265c3b9af92d56ea37 (diff) | |
download | Settings-2951b024dc4e741125631469d457d89d4bc0a359.tar.gz |
Wipe /data with ext4 before 16K OTA
16K developer option needs /data partition to be ext4. Wipe
the /data and reformat it to ext4 using RecoverySystem.
Test: m Settings && adb install -r $ANDROID_PRODUCT_OUT/system_ext/priv-app/Settings/Settings.apk
Test: adb shell cat /proc/mounts | grep f2fs
Bug: 295035851
Bug: 320700993
Change-Id: I7ca6f3a7e18d6dbe4e9791b3c83d149365941989
4 files changed, 192 insertions, 6 deletions
diff --git a/res/values/strings.xml b/res/values/strings.xml index def5890603a..f0794dd197f 100644 --- a/res/values/strings.xml +++ b/res/values/strings.xml @@ -11340,6 +11340,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> diff --git a/src/com/android/settings/development/Enable16kPagesPreferenceController.java b/src/com/android/settings/development/Enable16kPagesPreferenceController.java index 3f9da578bef..7049e79e5d4 100644 --- a/src/com/android/settings/development/Enable16kPagesPreferenceController.java +++ b/src/com/android/settings/development/Enable16kPagesPreferenceController.java @@ -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; + } } diff --git a/src/com/android/settings/development/EnableExt4DialogHost.java b/src/com/android/settings/development/EnableExt4DialogHost.java new file mode 100644 index 00000000000..6cbd7e18e2a --- /dev/null +++ b/src/com/android/settings/development/EnableExt4DialogHost.java @@ -0,0 +1,26 @@ +/* + * 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(); +} diff --git a/src/com/android/settings/development/EnableExt4WarningDialog.java b/src/com/android/settings/development/EnableExt4WarningDialog.java new file mode 100644 index 00000000000..c8ba521de2d --- /dev/null +++ b/src/com/android/settings/development/EnableExt4WarningDialog.java @@ -0,0 +1,93 @@ +/* + * 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(); + } +} |