Abort long-running benchmarks, report progress.

A typical storage device finishes the benchmark in under 10 seconds,
but some extremely slow devices can take minutes, resulting in a
confusing UX that looks like we've frozen.  Even worse, we keep
churning through all that I/O even though we know the device will
blow past our user-warning threshold.

So periodically check if we've timed out, and also use that to report
progress up into the Settings UI.

Test: manual
Bug: 62201209, 65639764, 67055204
Exempt-From-Owner-Approval: I wrote the original code.
Change-Id: Idd9d8c181651202d1434af879cff9355478a25c1
This commit is contained in:
Jeff Sharkey
2017-11-06 13:54:18 -07:00
parent c8b6833e13
commit 287d31f180
2 changed files with 46 additions and 11 deletions

View File

@@ -16,15 +16,19 @@
package com.android.settings.deviceinfo; package com.android.settings.deviceinfo;
import static com.android.settings.deviceinfo.StorageSettings.TAG;
import android.annotation.LayoutRes; import android.annotation.LayoutRes;
import android.app.Activity; import android.app.Activity;
import android.graphics.Color; import android.graphics.Color;
import android.os.Bundle; import android.os.Bundle;
import android.os.SystemClock;
import android.os.storage.DiskInfo; import android.os.storage.DiskInfo;
import android.os.storage.StorageEventListener; import android.os.storage.StorageEventListener;
import android.os.storage.StorageManager; import android.os.storage.StorageManager;
import android.os.storage.VolumeInfo; import android.os.storage.VolumeInfo;
import android.text.TextUtils; import android.text.TextUtils;
import android.util.Log;
import android.view.View; import android.view.View;
import android.view.ViewGroup; import android.view.ViewGroup;
import android.view.Window; import android.view.Window;
@@ -202,13 +206,27 @@ public abstract class StorageWizardBase extends Activity {
} }
protected VolumeInfo findFirstVolume(int type) { protected VolumeInfo findFirstVolume(int type) {
final List<VolumeInfo> vols = mStorage.getVolumes(); return findFirstVolume(type, 1);
for (VolumeInfo vol : vols) { }
if (Objects.equals(mDisk.getId(), vol.getDiskId()) && (vol.getType() == type)) {
return vol; protected VolumeInfo findFirstVolume(int type, int attempts) {
while (true) {
final List<VolumeInfo> vols = mStorage.getVolumes();
for (VolumeInfo vol : vols) {
if (Objects.equals(mDisk.getId(), vol.getDiskId()) && (vol.getType() == type)
&& (vol.getState() == VolumeInfo.STATE_MOUNTED)) {
return vol;
}
}
if (--attempts > 0) {
Log.w(TAG, "Missing mounted volume of type " + type + " hosted by disk "
+ mDisk.getId() + "; trying again");
SystemClock.sleep(250);
} else {
return null;
} }
} }
return null;
} }
private final StorageEventListener mStorageListener = new StorageEventListener() { private final StorageEventListener mStorageListener = new StorageEventListener() {

View File

@@ -16,15 +16,20 @@
package com.android.settings.deviceinfo; package com.android.settings.deviceinfo;
import static android.os.storage.VolumeInfo.TYPE_PRIVATE;
import static com.android.settings.deviceinfo.StorageSettings.TAG;
import android.app.AlertDialog; import android.app.AlertDialog;
import android.app.Dialog; import android.app.Dialog;
import android.app.DialogFragment;
import android.content.Context; import android.content.Context;
import android.content.DialogInterface; import android.content.DialogInterface;
import android.content.Intent; import android.content.Intent;
import android.content.pm.IPackageMoveObserver; import android.content.pm.IPackageMoveObserver;
import android.os.AsyncTask; import android.os.AsyncTask;
import android.os.Bundle; import android.os.Bundle;
import android.os.IVoldTaskListener;
import android.os.PersistableBundle;
import android.os.storage.DiskInfo; import android.os.storage.DiskInfo;
import android.os.storage.StorageManager; import android.os.storage.StorageManager;
import android.os.storage.VolumeInfo; import android.os.storage.VolumeInfo;
@@ -38,8 +43,8 @@ import com.android.settings.R;
import com.android.settings.core.instrumentation.InstrumentedDialogFragment; import com.android.settings.core.instrumentation.InstrumentedDialogFragment;
import java.util.Objects; import java.util.Objects;
import java.util.concurrent.CompletableFuture;
import static com.android.settings.deviceinfo.StorageSettings.TAG; import java.util.concurrent.TimeUnit;
public class StorageWizardFormatProgress extends StorageWizardBase { public class StorageWizardFormatProgress extends StorageWizardBase {
private static final String TAG_SLOW_WARNING = "slow_warning"; private static final String TAG_SLOW_WARNING = "slow_warning";
@@ -99,9 +104,21 @@ public class StorageWizardFormatProgress extends StorageWizardBase {
storage.partitionPrivate(activity.mDisk.getId()); storage.partitionPrivate(activity.mDisk.getId());
publishProgress(40); publishProgress(40);
final VolumeInfo privateVol = activity.findFirstVolume(VolumeInfo.TYPE_PRIVATE); final VolumeInfo privateVol = activity.findFirstVolume(TYPE_PRIVATE, 5);
mPrivateBench = storage.benchmark(privateVol.getId()); final CompletableFuture<PersistableBundle> result = new CompletableFuture<>();
mPrivateBench /= 1000000; storage.benchmark(privateVol.getId(), new IVoldTaskListener.Stub() {
@Override
public void onStatus(int status, PersistableBundle extras) {
// Map benchmark 0-100% progress onto 40-80%
publishProgress(40 + ((status * 40) / 100));
}
@Override
public void onFinished(int status, PersistableBundle extras) {
result.complete(extras);
}
});
mPrivateBench = result.get(60, TimeUnit.SECONDS).getLong("run", Long.MAX_VALUE);
// If we just adopted the device that had been providing // If we just adopted the device that had been providing
// physical storage, then automatically move storage to the // physical storage, then automatically move storage to the