Merge "Wipe /data with ext4 before 16K OTA" into main
This commit is contained in:
@@ -11620,6 +11620,12 @@
|
|||||||
<!-- Toast message when 16k OTA update fails -->
|
<!-- 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="toast_16k_update_failed_text">Failed to update kernel to 16KB pages compatible kernel.</string>
|
||||||
<string name="progress_16k_ota_title">Applying change</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. -->
|
<!-- DSU Loader. Do not translate. -->
|
||||||
|
|
||||||
<string name="dsu_loader_title" translatable="false">DSU Loader</string>
|
<string name="dsu_loader_title" translatable="false">DSU Loader</string>
|
||||||
|
@@ -22,6 +22,7 @@ import android.os.Handler;
|
|||||||
import android.os.ParcelFileDescriptor;
|
import android.os.ParcelFileDescriptor;
|
||||||
import android.os.PersistableBundle;
|
import android.os.PersistableBundle;
|
||||||
import android.os.PowerManager;
|
import android.os.PowerManager;
|
||||||
|
import android.os.RecoverySystem;
|
||||||
import android.os.SystemProperties;
|
import android.os.SystemProperties;
|
||||||
import android.os.SystemUpdateManager;
|
import android.os.SystemUpdateManager;
|
||||||
import android.os.UpdateEngine;
|
import android.os.UpdateEngine;
|
||||||
@@ -34,7 +35,6 @@ import android.widget.ProgressBar;
|
|||||||
import android.widget.Toast;
|
import android.widget.Toast;
|
||||||
|
|
||||||
import androidx.annotation.NonNull;
|
import androidx.annotation.NonNull;
|
||||||
import androidx.annotation.Nullable;
|
|
||||||
import androidx.annotation.VisibleForTesting;
|
import androidx.annotation.VisibleForTesting;
|
||||||
import androidx.appcompat.app.AlertDialog;
|
import androidx.appcompat.app.AlertDialog;
|
||||||
import androidx.core.content.ContextCompat;
|
import androidx.core.content.ContextCompat;
|
||||||
@@ -54,6 +54,7 @@ import com.google.common.util.concurrent.MoreExecutors;
|
|||||||
import java.io.BufferedReader;
|
import java.io.BufferedReader;
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.FileNotFoundException;
|
import java.io.FileNotFoundException;
|
||||||
|
import java.io.FileReader;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
import java.io.InputStreamReader;
|
import java.io.InputStreamReader;
|
||||||
@@ -68,7 +69,8 @@ import java.util.zip.ZipFile;
|
|||||||
public class Enable16kPagesPreferenceController extends DeveloperOptionsPreferenceController
|
public class Enable16kPagesPreferenceController extends DeveloperOptionsPreferenceController
|
||||||
implements Preference.OnPreferenceChangeListener,
|
implements Preference.OnPreferenceChangeListener,
|
||||||
PreferenceControllerMixin,
|
PreferenceControllerMixin,
|
||||||
Enable16kbPagesDialogHost {
|
Enable16kbPagesDialogHost,
|
||||||
|
EnableExt4DialogHost {
|
||||||
|
|
||||||
private static final String TAG = "Enable16kPages";
|
private static final String TAG = "Enable16kPages";
|
||||||
private static final String REBOOT_REASON = "toggle16k";
|
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;
|
private static final int OFFSET_TO_FILE_NAME = 30;
|
||||||
public static final String EXPERIMENTAL_UPDATE_TITLE = "Android 16K Kernel Experimental Update";
|
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 boolean mEnable16k;
|
||||||
|
|
||||||
private final ListeningExecutorService mExecutorService =
|
private final ListeningExecutorService mExecutorService =
|
||||||
@@ -96,9 +98,9 @@ public class Enable16kPagesPreferenceController extends DeveloperOptionsPreferen
|
|||||||
private AlertDialog mProgressDialog;
|
private AlertDialog mProgressDialog;
|
||||||
|
|
||||||
public Enable16kPagesPreferenceController(
|
public Enable16kPagesPreferenceController(
|
||||||
@NonNull Context context, @Nullable DevelopmentSettingsDashboardFragment fragment) {
|
@NonNull Context context, @NonNull DevelopmentSettingsDashboardFragment fragment) {
|
||||||
super(context);
|
super(context);
|
||||||
mFragment = fragment;
|
this.mFragment = fragment;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -114,6 +116,10 @@ public class Enable16kPagesPreferenceController extends DeveloperOptionsPreferen
|
|||||||
@Override
|
@Override
|
||||||
public boolean onPreferenceChange(Preference preference, Object newValue) {
|
public boolean onPreferenceChange(Preference preference, Object newValue) {
|
||||||
mEnable16k = (Boolean) newValue;
|
mEnable16k = (Boolean) newValue;
|
||||||
|
if (isDataf2fs()) {
|
||||||
|
EnableExt4WarningDialog.show(mFragment, this);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
Enable16kPagesWarningDialog.show(mFragment, this, mEnable16k);
|
Enable16kPagesWarningDialog.show(mFragment, this, mEnable16k);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -162,7 +168,7 @@ public class Enable16kPagesPreferenceController extends DeveloperOptionsPreferen
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onFailure(Throwable t) {
|
public void onFailure(@NonNull Throwable t) {
|
||||||
hideProgressDialog();
|
hideProgressDialog();
|
||||||
Log.e(TAG, "Failed to call applyPayload of UpdateEngineStable!");
|
Log.e(TAG, "Failed to call applyPayload of UpdateEngineStable!");
|
||||||
displayToast(mContext.getString(R.string.toast_16k_update_failed_text));
|
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();
|
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 {
|
private class OtaUpdateCallback extends UpdateEngineStableCallback {
|
||||||
UpdateEngineStable mUpdateEngineStable;
|
UpdateEngineStable mUpdateEngineStable;
|
||||||
|
|
||||||
@@ -357,4 +398,24 @@ public class Enable16kPagesPreferenceController extends DeveloperOptionsPreferen
|
|||||||
infoBundle.putString(SystemUpdateManager.KEY_TITLE, EXPERIMENTAL_UPDATE_TITLE);
|
infoBundle.putString(SystemUpdateManager.KEY_TITLE, EXPERIMENTAL_UPDATE_TITLE);
|
||||||
return infoBundle;
|
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;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@@ -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();
|
||||||
|
}
|
@@ -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();
|
||||||
|
}
|
||||||
|
}
|
Reference in New Issue
Block a user