Merge changes I81b41460,I81561c19

* changes:
  DSU service: Show which partition is being installed in notification
  DSU service: Weighted progress bar
This commit is contained in:
Yi-yo Chiang
2022-03-28 03:31:10 +00:00
committed by Gerrit Code Review
3 changed files with 163 additions and 62 deletions

View File

@@ -112,18 +112,20 @@ public class DynamicSystemInstallationService extends Service
private static final int EVENT_DSU_INSTALL_FAILED = 120002; private static final int EVENT_DSU_INSTALL_FAILED = 120002;
protected static void logEventProgressUpdate( protected static void logEventProgressUpdate(
String partition, String partitionName,
long installedSize, long installedBytes,
long partitionSize, long totalBytes,
int partitionNumber, int partitionNumber,
int totalPartitionNumber) { int totalPartitionNumber,
int totalProgressPercentage) {
EventLog.writeEvent( EventLog.writeEvent(
EVENT_DSU_PROGRESS_UPDATE, EVENT_DSU_PROGRESS_UPDATE,
partition, partitionName,
installedSize, installedBytes,
partitionSize, totalBytes,
partitionNumber, partitionNumber,
totalPartitionNumber); totalPartitionNumber,
totalProgressPercentage);
} }
protected static void logEventComplete() { protected static void logEventComplete() {
@@ -231,10 +233,11 @@ public class DynamicSystemInstallationService extends Service
public void onProgressUpdate(InstallationAsyncTask.Progress progress) { public void onProgressUpdate(InstallationAsyncTask.Progress progress) {
logEventProgressUpdate( logEventProgressUpdate(
progress.partitionName, progress.partitionName,
progress.installedSize, progress.installedBytes,
progress.partitionSize, progress.totalBytes,
progress.partitionNumber, progress.partitionNumber,
progress.totalPartitionNumber); progress.totalPartitionNumber,
progress.totalProgressPercentage);
mInstallTaskProgress = progress; mInstallTaskProgress = progress;
postStatus(STATUS_IN_PROGRESS, CAUSE_NOT_SPECIFIED, null); postStatus(STATUS_IN_PROGRESS, CAUSE_NOT_SPECIFIED, null);
@@ -483,23 +486,46 @@ public class DynamicSystemInstallationService extends Service
switch (status) { switch (status) {
case STATUS_IN_PROGRESS: case STATUS_IN_PROGRESS:
builder.setContentText(getString(R.string.notification_install_inprogress)); String msgInProgress = getString(R.string.notification_install_inprogress);
if (mInstallTaskProgress != null) { if (mInstallTaskProgress == null) {
int max = 1024; builder.setContentText(msgInProgress);
int progress = 0; } else {
if (mInstallTaskProgress.totalPartitionNumber > 0) {
builder.setContentText(
String.format(
"%s: %s partition [%d/%d]",
msgInProgress,
mInstallTaskProgress.partitionName,
mInstallTaskProgress.partitionNumber,
mInstallTaskProgress.totalPartitionNumber));
int currentMax = max >> mInstallTaskProgress.partitionNumber; // totalProgressPercentage is defined iff totalPartitionNumber is defined
progress = max - currentMax * 2; builder.setProgress(
100,
mInstallTaskProgress.totalProgressPercentage,
/* indeterminate = */ false);
} else {
builder.setContentText(
String.format(
"%s: %s partition",
msgInProgress, mInstallTaskProgress.partitionName));
long currentProgress = int max = 1024;
(mInstallTaskProgress.installedSize >> 20) int progress = 0;
* currentMax
/ Math.max(mInstallTaskProgress.partitionSize >> 20, 1);
progress += (int) currentProgress; int currentMax = max >> mInstallTaskProgress.partitionNumber;
progress = max - currentMax * 2;
builder.setProgress(max, progress, false); long currentProgress =
(mInstallTaskProgress.installedBytes >> 20)
* currentMax
/ Math.max(mInstallTaskProgress.totalBytes >> 20, 1);
progress += (int) currentProgress;
builder.setProgress(max, progress, false);
}
} }
builder.addAction(new Notification.Action.Builder( builder.addAction(new Notification.Action.Builder(
null, getString(R.string.notification_action_cancel), null, getString(R.string.notification_action_cancel),
@@ -609,10 +635,11 @@ public class DynamicSystemInstallationService extends Service
if (status == STATUS_IN_PROGRESS && mInstallTaskProgress != null) { if (status == STATUS_IN_PROGRESS && mInstallTaskProgress != null) {
msg.append( msg.append(
String.format( String.format(
", partition name: %s, progress: %d/%d", ", partition name: %s, progress: %d/%d, total_progress: %d%%",
mInstallTaskProgress.partitionName, mInstallTaskProgress.partitionName,
mInstallTaskProgress.installedSize, mInstallTaskProgress.installedBytes,
mInstallTaskProgress.partitionSize)); mInstallTaskProgress.totalBytes,
mInstallTaskProgress.totalProgressPercentage));
} }
if (detail != null) { if (detail != null) {
msg.append(", detail: " + detail); msg.append(", detail: " + detail);
@@ -639,7 +666,7 @@ public class DynamicSystemInstallationService extends Service
// TODO: send more info to the clients // TODO: send more info to the clients
if (mInstallTaskProgress != null) { if (mInstallTaskProgress != null) {
bundle.putLong( bundle.putLong(
DynamicSystemClient.KEY_INSTALLED_SIZE, mInstallTaskProgress.installedSize); DynamicSystemClient.KEY_INSTALLED_SIZE, mInstallTaskProgress.installedBytes);
} }
if (detail != null) { if (detail != null) {

View File

@@ -2,6 +2,6 @@
option java_package com.android.dynsystem option java_package com.android.dynsystem
120000 dsu_progress_update (partition|3),(installed_size|2|5),(partition_size|2|5),(partition_number|1|5),(total_partition_number|1|5) 120000 dsu_progress_update (partition_name|3),(installed_bytes|2|5),(total_bytes|2|5),(partition_number|1|5),(total_partition_number|1|5),(total_progress_percentage|1|5)
120001 dsu_install_complete 120001 dsu_install_complete
120002 dsu_install_failed (cause|3) 120002 dsu_install_failed (cause|3)

View File

@@ -113,22 +113,25 @@ class InstallationAsyncTask extends AsyncTask<String, Long, Throwable> {
static class Progress { static class Progress {
public final String partitionName; public final String partitionName;
public final long installedSize; public final long installedBytes;
public final long partitionSize; public final long totalBytes;
public final int partitionNumber; public final int partitionNumber;
public final int totalPartitionNumber; public final int totalPartitionNumber;
public final int totalProgressPercentage;
Progress( Progress(
String partitionName, String partitionName,
long installedSize, long installedBytes,
long partitionSize, long totalBytes,
int partitionNumber, int partitionNumber,
int totalPartitionNumber) { int totalPartitionNumber,
int totalProgressPercentage) {
this.partitionName = partitionName; this.partitionName = partitionName;
this.installedSize = installedSize; this.installedBytes = installedBytes;
this.partitionSize = partitionSize; this.totalBytes = totalBytes;
this.partitionNumber = partitionNumber; this.partitionNumber = partitionNumber;
this.totalPartitionNumber = totalPartitionNumber; this.totalPartitionNumber = totalPartitionNumber;
this.totalProgressPercentage = totalProgressPercentage;
} }
} }
@@ -149,20 +152,28 @@ class InstallationAsyncTask extends AsyncTask<String, Long, Throwable> {
private final ProgressListener mListener; private final ProgressListener mListener;
private final boolean mIsNetworkUrl; private final boolean mIsNetworkUrl;
private final boolean mIsDeviceBootloaderUnlocked; private final boolean mIsDeviceBootloaderUnlocked;
private final boolean mWantScratchPartition;
private DynamicSystemManager.Session mInstallationSession; private DynamicSystemManager.Session mInstallationSession;
private KeyRevocationList mKeyRevocationList; private KeyRevocationList mKeyRevocationList;
private boolean mIsZip; private boolean mIsZip;
private boolean mIsCompleted; private boolean mIsCompleted;
private String mPartitionName;
private long mPartitionSize;
private int mPartitionNumber;
private int mTotalPartitionNumber;
private InputStream mStream; private InputStream mStream;
private ZipFile mZipFile; private ZipFile mZipFile;
private static final double PROGRESS_READONLY_PARTITION_WEIGHT = 0.8;
private static final double PROGRESS_WRITABLE_PARTITION_WEIGHT = 0.2;
private String mProgressPartitionName;
private long mProgressTotalBytes;
private int mProgressPartitionNumber;
private boolean mProgressPartitionIsReadonly;
private int mProgressCompletedReadonlyPartitions;
private int mProgressCompletedWritablePartitions;
private int mTotalReadonlyPartitions;
private int mTotalWritablePartitions;
private int mTotalPartitionNumber;
InstallationAsyncTask( InstallationAsyncTask(
String url, String url,
String dsuSlot, String dsuSlot,
@@ -193,21 +204,18 @@ class InstallationAsyncTask extends AsyncTask<String, Long, Throwable> {
(pdbManager != null) (pdbManager != null)
&& (pdbManager.getFlashLockState() && (pdbManager.getFlashLockState()
== PersistentDataBlockManager.FLASH_LOCK_UNLOCKED); == PersistentDataBlockManager.FLASH_LOCK_UNLOCKED);
mWantScratchPartition = Build.IS_DEBUGGABLE;
} }
@Override @Override
protected Throwable doInBackground(String... voids) { protected Throwable doInBackground(String... voids) {
Log.d(TAG, "Start doInBackground(), URL: " + mUrl); Log.d(TAG, "Start doInBackground(), URL: " + mUrl);
final boolean wantScratchPartition = Build.IS_DEBUGGABLE;
try { try {
// call DynamicSystemManager to cleanup stuff // call DynamicSystemManager to cleanup stuff
mDynSystem.remove(); mDynSystem.remove();
verifyAndPrepare(); verifyAndPrepare();
if (wantScratchPartition) {
++mTotalPartitionNumber;
}
mDynSystem.startInstallation(mDsuSlot); mDynSystem.startInstallation(mDsuSlot);
@@ -226,7 +234,7 @@ class InstallationAsyncTask extends AsyncTask<String, Long, Throwable> {
return null; return null;
} }
if (wantScratchPartition) { if (mWantScratchPartition) {
// If host is debuggable, then install a scratch partition so that we can do // If host is debuggable, then install a scratch partition so that we can do
// adb remount in the guest system. // adb remount in the guest system.
try { try {
@@ -290,14 +298,54 @@ class InstallationAsyncTask extends AsyncTask<String, Long, Throwable> {
} }
@Override @Override
protected void onProgressUpdate(Long... installedSize) { protected void onProgressUpdate(Long... progress) {
final long installedBytes = progress[0];
int totalProgressPercentage = 0;
if (mTotalPartitionNumber > 0) {
final double readonlyPartitionWeight =
mTotalReadonlyPartitions > 0
? PROGRESS_READONLY_PARTITION_WEIGHT / mTotalReadonlyPartitions
: 0;
final double writablePartitionWeight =
mTotalWritablePartitions > 0
? PROGRESS_WRITABLE_PARTITION_WEIGHT / mTotalWritablePartitions
: 0;
double totalProgress = 0.0;
if (mProgressTotalBytes > 0) {
totalProgress +=
(mProgressPartitionIsReadonly
? readonlyPartitionWeight
: writablePartitionWeight)
* installedBytes
/ mProgressTotalBytes;
}
totalProgress += readonlyPartitionWeight * mProgressCompletedReadonlyPartitions;
totalProgress += writablePartitionWeight * mProgressCompletedWritablePartitions;
totalProgressPercentage = (int) (totalProgress * 100);
}
mListener.onProgressUpdate( mListener.onProgressUpdate(
new Progress( new Progress(
mPartitionName, mProgressPartitionName,
installedSize[0], installedBytes,
mPartitionSize, mProgressTotalBytes,
mPartitionNumber, mProgressPartitionNumber,
mTotalPartitionNumber)); mTotalPartitionNumber,
totalProgressPercentage));
}
private void initPartitionProgress(String partitionName, long totalBytes, boolean readonly) {
if (mProgressPartitionNumber > 0) {
// Assume previous partition completed successfully.
if (mProgressPartitionIsReadonly) {
++mProgressCompletedReadonlyPartitions;
} else {
++mProgressCompletedWritablePartitions;
}
}
mProgressPartitionName = partitionName;
mProgressTotalBytes = totalBytes;
mProgressPartitionIsReadonly = readonly;
++mProgressPartitionNumber;
} }
private void verifyAndPrepare() throws Exception { private void verifyAndPrepare() throws Exception {
@@ -314,16 +362,12 @@ class InstallationAsyncTask extends AsyncTask<String, Long, Throwable> {
throw new UnsupportedFormatException( throw new UnsupportedFormatException(
String.format(Locale.US, "Unsupported file format: %s", mUrl)); String.format(Locale.US, "Unsupported file format: %s", mUrl));
} }
// At least two partitions, {system, userdata}
mTotalPartitionNumber = 2;
if (mIsNetworkUrl) { if (mIsNetworkUrl) {
mStream = new URL(mUrl).openStream(); mStream = new URL(mUrl).openStream();
} else if (URLUtil.isFileUrl(mUrl)) { } else if (URLUtil.isFileUrl(mUrl)) {
if (mIsZip) { if (mIsZip) {
mZipFile = new ZipFile(new File(new URL(mUrl).toURI())); mZipFile = new ZipFile(new File(new URL(mUrl).toURI()));
// {*.img in zip} + {userdata}
mTotalPartitionNumber = calculateNumberOfImagesInLocalZip(mZipFile) + 1;
} else { } else {
mStream = new URL(mUrl).openStream(); mStream = new URL(mUrl).openStream();
} }
@@ -334,6 +378,32 @@ class InstallationAsyncTask extends AsyncTask<String, Long, Throwable> {
String.format(Locale.US, "Unsupported URL: %s", mUrl)); String.format(Locale.US, "Unsupported URL: %s", mUrl));
} }
boolean hasTotalPartitionNumber = false;
if (mIsZip) {
if (mZipFile != null) {
// {*.img in zip} + {userdata}
hasTotalPartitionNumber = true;
mTotalReadonlyPartitions = calculateNumberOfImagesInLocalZip(mZipFile);
mTotalWritablePartitions = 1;
} else {
// TODO: Come up with a way to retrieve the number of total partitions from
// network URL.
}
} else {
// gzip has exactly two partitions, {system, userdata}
hasTotalPartitionNumber = true;
mTotalReadonlyPartitions = 1;
mTotalWritablePartitions = 1;
}
if (hasTotalPartitionNumber) {
if (mWantScratchPartition) {
// {scratch}
++mTotalWritablePartitions;
}
mTotalPartitionNumber = mTotalReadonlyPartitions + mTotalWritablePartitions;
}
try { try {
String listUrl = mContext.getString(R.string.key_revocation_list_url); String listUrl = mContext.getString(R.string.key_revocation_list_url);
mKeyRevocationList = KeyRevocationList.fromUrl(new URL(listUrl)); mKeyRevocationList = KeyRevocationList.fromUrl(new URL(listUrl));
@@ -370,9 +440,7 @@ class InstallationAsyncTask extends AsyncTask<String, Long, Throwable> {
} }
}; };
mPartitionName = partitionName; initPartitionProgress(partitionName, partitionSize, /* readonly = */ false);
mPartitionSize = partitionSize;
++mPartitionNumber;
publishProgress(/* installedSize = */ 0L); publishProgress(/* installedSize = */ 0L);
long prevInstalledSize = 0; long prevInstalledSize = 0;
@@ -396,6 +464,10 @@ class InstallationAsyncTask extends AsyncTask<String, Long, Throwable> {
} }
} }
if (prevInstalledSize != partitionSize) {
publishProgress(partitionSize);
}
if (mInstallationSession == null) { if (mInstallationSession == null) {
throw new IOException( throw new IOException(
"Failed to start installation with requested size: " + partitionSize); "Failed to start installation with requested size: " + partitionSize);
@@ -559,9 +631,7 @@ class InstallationAsyncTask extends AsyncTask<String, Long, Throwable> {
mInstallationSession.setAshmem(pfd, memoryFile.length()); mInstallationSession.setAshmem(pfd, memoryFile.length());
mPartitionName = partitionName; initPartitionProgress(partitionName, partitionSize, /* readonly = */ true);
mPartitionSize = partitionSize;
++mPartitionNumber;
publishProgress(/* installedSize = */ 0L); publishProgress(/* installedSize = */ 0L);
long prevInstalledSize = 0; long prevInstalledSize = 0;
@@ -588,6 +658,10 @@ class InstallationAsyncTask extends AsyncTask<String, Long, Throwable> {
} }
} }
if (prevInstalledSize != partitionSize) {
publishProgress(partitionSize);
}
AvbPublicKey avbPublicKey = new AvbPublicKey(); AvbPublicKey avbPublicKey = new AvbPublicKey();
if (!mInstallationSession.getAvbPublicKey(avbPublicKey)) { if (!mInstallationSession.getAvbPublicKey(avbPublicKey)) {
imageValidationThrowOrWarning(new PublicKeyException("getAvbPublicKey() failed")); imageValidationThrowOrWarning(new PublicKeyException("getAvbPublicKey() failed"));