DSU installation service: Add event log tags

Log important events to the 'events' buffer so other tools can robustly
and progmatically parse the DSU logs.

Bug: 224909776
Test: adb logcat -b events -v descriptive \
  '*:S dsu_progress_update dsu_install_complete dsu_install_failed'
Change-Id: Iac8d3ec31f51eb9410eb631487e26b4ccb0ccf81
This commit is contained in:
Yi-Yo Chiang
2022-03-16 23:52:15 +08:00
parent 634b3fec76
commit d43cfe48e9
4 changed files with 174 additions and 60 deletions

View File

@@ -22,6 +22,9 @@ android_app {
defaults: ["platform_app_defaults"],
srcs: ["src/**/*.java"],
static_libs: [
"DynamicSystemInstallationService-logtags",
],
resource_dirs: ["res"],
certificate: "platform",
@@ -32,3 +35,8 @@ android_app {
enabled: false,
},
}
java_library {
name: "DynamicSystemInstallationService-logtags",
srcs: ["src/**/*.logtags"],
}

View File

@@ -58,6 +58,7 @@ import android.os.RemoteException;
import android.os.image.DynamicSystemClient;
import android.os.image.DynamicSystemManager;
import android.text.TextUtils;
import android.util.EventLog;
import android.util.Log;
import android.widget.Toast;
@@ -103,6 +104,36 @@ public class DynamicSystemInstallationService extends Service
private static final String NOTIFICATION_CHANNEL_ID = "com.android.dynsystem";
private static final int NOTIFICATION_ID = 1;
/*
* Event log tags
*/
private static final int EVENT_DSU_PROGRESS_UPDATE = 120000;
private static final int EVENT_DSU_INSTALL_COMPLETE = 120001;
private static final int EVENT_DSU_INSTALL_FAILED = 120002;
protected static void logEventProgressUpdate(
String partition,
long installedSize,
long partitionSize,
int partitionNumber,
int totalPartitionNumber) {
EventLog.writeEvent(
EVENT_DSU_PROGRESS_UPDATE,
partition,
installedSize,
partitionSize,
partitionNumber,
totalPartitionNumber);
}
protected static void logEventComplete() {
EventLog.writeEvent(EVENT_DSU_INSTALL_COMPLETE);
}
protected static void logEventFailed(String cause) {
EventLog.writeEvent(EVENT_DSU_INSTALL_FAILED, cause);
}
/*
* IPC
*/
@@ -132,15 +163,10 @@ public class DynamicSystemInstallationService extends Service
private DynamicSystemManager mDynSystem;
private NotificationManager mNM;
private int mNumInstalledPartitions;
private String mCurrentPartitionName;
private long mCurrentPartitionSize;
private long mCurrentPartitionInstalledSize;
// This is for testing only now
private boolean mEnableWhenCompleted;
private InstallationAsyncTask.Progress mInstallTaskProgress;
private InstallationAsyncTask mInstallTask;
@@ -203,17 +229,21 @@ public class DynamicSystemInstallationService extends Service
@Override
public void onProgressUpdate(InstallationAsyncTask.Progress progress) {
mCurrentPartitionName = progress.partitionName;
mCurrentPartitionSize = progress.partitionSize;
mCurrentPartitionInstalledSize = progress.installedSize;
mNumInstalledPartitions = progress.numInstalledPartitions;
logEventProgressUpdate(
progress.partitionName,
progress.installedSize,
progress.partitionSize,
progress.partitionNumber,
progress.totalPartitionNumber);
mInstallTaskProgress = progress;
postStatus(STATUS_IN_PROGRESS, CAUSE_NOT_SPECIFIED, null);
}
@Override
public void onResult(int result, Throwable detail) {
if (result == RESULT_OK) {
logEventComplete();
postStatus(STATUS_READY, CAUSE_INSTALL_COMPLETED, null);
// For testing: enable DSU and restart the device when install completed
@@ -223,6 +253,12 @@ public class DynamicSystemInstallationService extends Service
return;
}
if (result == RESULT_CANCELLED) {
logEventFailed("Dynamic System installation task is canceled by the user.");
} else {
logEventFailed("error: " + detail);
}
boolean removeNotification = false;
switch (result) {
case RESULT_CANCELLED:
@@ -251,16 +287,20 @@ public class DynamicSystemInstallationService extends Service
private void executeInstallCommand(Intent intent) {
if (!verifyRequest(intent)) {
Log.e(TAG, "Verification failed. Did you use VerificationActivity?");
logEventFailed("VerificationActivity");
return;
}
if (mInstallTask != null) {
Log.e(TAG, "There is already an installation task running");
logEventFailed("There is already an ongoing installation task.");
return;
}
if (isInDynamicSystem()) {
Log.e(TAG, "We are already running in DynamicSystem");
logEventFailed(
"Cannot start a Dynamic System installation task within a Dynamic System.");
return;
}
@@ -445,19 +485,22 @@ public class DynamicSystemInstallationService extends Service
case STATUS_IN_PROGRESS:
builder.setContentText(getString(R.string.notification_install_inprogress));
int max = 1024;
int progress = 0;
if (mInstallTaskProgress != null) {
int max = 1024;
int progress = 0;
int currentMax = max >> (mNumInstalledPartitions + 1);
progress = max - currentMax * 2;
int currentMax = max >> mInstallTaskProgress.partitionNumber;
progress = max - currentMax * 2;
long currentProgress = (mCurrentPartitionInstalledSize >> 20) * currentMax
/ Math.max(mCurrentPartitionSize >> 20, 1);
long currentProgress =
(mInstallTaskProgress.installedSize >> 20)
* currentMax
/ Math.max(mInstallTaskProgress.partitionSize >> 20, 1);
progress += (int) currentProgress;
builder.setProgress(max, progress, false);
progress += (int) currentProgress;
builder.setProgress(max, progress, false);
}
builder.addAction(new Notification.Action.Builder(
null, getString(R.string.notification_action_cancel),
createPendingIntent(ACTION_CANCEL_INSTALL)).build());
@@ -563,13 +606,13 @@ public class DynamicSystemInstallationService extends Service
StringBuilder msg = new StringBuilder();
msg.append("status: " + statusString + ", cause: " + causeString);
if (status == STATUS_IN_PROGRESS) {
if (status == STATUS_IN_PROGRESS && mInstallTaskProgress != null) {
msg.append(
String.format(
", partition name: %s, progress: %d/%d",
mCurrentPartitionName,
mCurrentPartitionInstalledSize,
mCurrentPartitionSize));
mInstallTaskProgress.partitionName,
mInstallTaskProgress.installedSize,
mInstallTaskProgress.partitionSize));
}
if (detail != null) {
msg.append(", detail: " + detail);
@@ -594,7 +637,10 @@ public class DynamicSystemInstallationService extends Service
Bundle bundle = new Bundle();
// TODO: send more info to the clients
bundle.putLong(DynamicSystemClient.KEY_INSTALLED_SIZE, mCurrentPartitionInstalledSize);
if (mInstallTaskProgress != null) {
bundle.putLong(
DynamicSystemClient.KEY_INSTALLED_SIZE, mInstallTaskProgress.installedSize);
}
if (detail != null) {
bundle.putSerializable(DynamicSystemClient.KEY_EXCEPTION_DETAIL,

View File

@@ -0,0 +1,7 @@
# See system/logging/logcat/event.logtags for a description of the format of this file.
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)
120001 dsu_install_complete
120002 dsu_install_failed (cause|3)

View File

@@ -44,7 +44,7 @@ import java.util.zip.ZipEntry;
import java.util.zip.ZipFile;
import java.util.zip.ZipInputStream;
class InstallationAsyncTask extends AsyncTask<String, InstallationAsyncTask.Progress, Throwable> {
class InstallationAsyncTask extends AsyncTask<String, Long, Throwable> {
private static final String TAG = "InstallationAsyncTask";
@@ -106,14 +106,22 @@ class InstallationAsyncTask extends AsyncTask<String, InstallationAsyncTask.Prog
static class Progress {
public final String partitionName;
public final long installedSize;
public final long partitionSize;
public final int numInstalledPartitions;
public long installedSize;
public final int partitionNumber;
public final int totalPartitionNumber;
Progress(String partitionName, long partitionSize, int numInstalledPartitions) {
Progress(
String partitionName,
long installedSize,
long partitionSize,
int partitionNumber,
int totalPartitionNumber) {
this.partitionName = partitionName;
this.installedSize = installedSize;
this.partitionSize = partitionSize;
this.numInstalledPartitions = numInstalledPartitions;
this.partitionNumber = partitionNumber;
this.totalPartitionNumber = totalPartitionNumber;
}
}
@@ -139,7 +147,10 @@ class InstallationAsyncTask extends AsyncTask<String, InstallationAsyncTask.Prog
private boolean mIsZip;
private boolean mIsCompleted;
private int mNumInstalledPartitions;
private String mPartitionName;
private long mPartitionSize;
private int mPartitionNumber;
private int mTotalPartitionNumber;
private InputStream mStream;
private ZipFile mZipFile;
@@ -175,11 +186,15 @@ class InstallationAsyncTask extends AsyncTask<String, InstallationAsyncTask.Prog
protected Throwable doInBackground(String... voids) {
Log.d(TAG, "Start doInBackground(), URL: " + mUrl);
final boolean wantScratchPartition = Build.IS_DEBUGGABLE;
try {
// call DynamicSystemManager to cleanup stuff
mDynSystem.remove();
verifyAndPrepare();
if (wantScratchPartition) {
++mTotalPartitionNumber;
}
mDynSystem.startInstallation(mDsuSlot);
@@ -198,7 +213,7 @@ class InstallationAsyncTask extends AsyncTask<String, InstallationAsyncTask.Prog
return null;
}
if (Build.IS_DEBUGGABLE) {
if (wantScratchPartition) {
// If host is debuggable, then install a scratch partition so that we can do
// adb remount in the guest system.
try {
@@ -262,9 +277,14 @@ class InstallationAsyncTask extends AsyncTask<String, InstallationAsyncTask.Prog
}
@Override
protected void onProgressUpdate(Progress... values) {
Progress progress = values[0];
mListener.onProgressUpdate(progress);
protected void onProgressUpdate(Long... installedSize) {
mListener.onProgressUpdate(
new Progress(
mPartitionName,
installedSize[0],
mPartitionSize,
mPartitionNumber,
mTotalPartitionNumber));
}
private void verifyAndPrepare() throws Exception {
@@ -281,12 +301,16 @@ class InstallationAsyncTask extends AsyncTask<String, InstallationAsyncTask.Prog
throw new UnsupportedFormatException(
String.format(Locale.US, "Unsupported file format: %s", mUrl));
}
// At least two partitions, {system, userdata}
mTotalPartitionNumber = 2;
if (mIsNetworkUrl) {
mStream = new URL(mUrl).openStream();
} else if (URLUtil.isFileUrl(mUrl)) {
if (mIsZip) {
mZipFile = new ZipFile(new File(new URL(mUrl).toURI()));
// {*.img in zip} + {userdata}
mTotalPartitionNumber = calculateNumberOfImagesInLocalZip(mZipFile) + 1;
} else {
mStream = new URL(mUrl).openStream();
}
@@ -333,9 +357,13 @@ class InstallationAsyncTask extends AsyncTask<String, InstallationAsyncTask.Prog
}
};
thread.start();
Progress progress = new Progress(partitionName, partitionSize, mNumInstalledPartitions++);
mPartitionName = partitionName;
mPartitionSize = partitionSize;
++mPartitionNumber;
publishProgress(/* installedSize = */ 0L);
long prevInstalledSize = 0;
thread.start();
while (thread.isAlive()) {
if (isCancelled()) {
return;
@@ -343,9 +371,9 @@ class InstallationAsyncTask extends AsyncTask<String, InstallationAsyncTask.Prog
final long installedSize = mDynSystem.getInstallationProgress().bytes_processed;
if (installedSize > progress.installedSize + MIN_PROGRESS_TO_PUBLISH) {
progress.installedSize = installedSize;
publishProgress(progress);
if (installedSize > prevInstalledSize + MIN_PROGRESS_TO_PUBLISH) {
publishProgress(installedSize);
prevInstalledSize = installedSize;
}
try {
@@ -392,14 +420,42 @@ class InstallationAsyncTask extends AsyncTask<String, InstallationAsyncTask.Prog
installImage("system", mSystemSize, new GZIPInputStream(mStream));
}
private boolean shouldInstallEntry(String name) {
if (!name.endsWith(".img")) {
return false;
}
String partitionName = name.substring(0, name.length() - 4);
if (UNSUPPORTED_PARTITIONS.contains(partitionName)) {
return false;
}
return true;
}
private int calculateNumberOfImagesInLocalZip(ZipFile zipFile) {
int total = 0;
Enumeration<? extends ZipEntry> entries = zipFile.entries();
while (entries.hasMoreElements()) {
ZipEntry entry = entries.nextElement();
if (shouldInstallEntry(entry.getName())) {
++total;
}
}
return total;
}
private void installStreamingZipUpdate() throws IOException, ImageValidationException {
Log.d(TAG, "To install a streaming ZIP update");
ZipInputStream zis = new ZipInputStream(mStream);
ZipEntry zipEntry = null;
ZipEntry entry = null;
while ((zipEntry = zis.getNextEntry()) != null) {
installImageFromAnEntry(zipEntry, zis);
while ((entry = zis.getNextEntry()) != null) {
String name = entry.getName();
if (shouldInstallEntry(name)) {
installImageFromAnEntry(entry, zis);
} else {
Log.d(TAG, name + " installation is not supported, skip it.");
}
if (isCancelled()) {
break;
@@ -414,7 +470,12 @@ class InstallationAsyncTask extends AsyncTask<String, InstallationAsyncTask.Prog
while (entries.hasMoreElements()) {
ZipEntry entry = entries.nextElement();
installImageFromAnEntry(entry, mZipFile.getInputStream(entry));
String name = entry.getName();
if (shouldInstallEntry(name)) {
installImageFromAnEntry(entry, mZipFile.getInputStream(entry));
} else {
Log.d(TAG, name + " installation is not supported, skip it.");
}
if (isCancelled()) {
break;
@@ -422,28 +483,16 @@ class InstallationAsyncTask extends AsyncTask<String, InstallationAsyncTask.Prog
}
}
private boolean installImageFromAnEntry(ZipEntry entry, InputStream is)
private void installImageFromAnEntry(ZipEntry entry, InputStream is)
throws IOException, ImageValidationException {
String name = entry.getName();
Log.d(TAG, "ZipEntry: " + name);
if (!name.endsWith(".img")) {
return false;
}
String partitionName = name.substring(0, name.length() - 4);
if (UNSUPPORTED_PARTITIONS.contains(partitionName)) {
Log.d(TAG, name + " installation is not supported, skip it.");
return false;
}
long uncompressedSize = entry.getSize();
installImage(partitionName, uncompressedSize, is);
return true;
}
private void installImage(String partitionName, long uncompressedSize, InputStream is)
@@ -497,8 +546,12 @@ class InstallationAsyncTask extends AsyncTask<String, InstallationAsyncTask.Prog
mInstallationSession.setAshmem(pfd, READ_BUFFER_SIZE);
Progress progress = new Progress(partitionName, partitionSize, mNumInstalledPartitions++);
mPartitionName = partitionName;
mPartitionSize = partitionSize;
++mPartitionNumber;
publishProgress(/* installedSize = */ 0L);
long prevInstalledSize = 0;
long installedSize = 0;
byte[] bytes = new byte[READ_BUFFER_SIZE];
int numBytesRead;
@@ -516,9 +569,9 @@ class InstallationAsyncTask extends AsyncTask<String, InstallationAsyncTask.Prog
installedSize += numBytesRead;
if (installedSize > progress.installedSize + MIN_PROGRESS_TO_PUBLISH) {
progress.installedSize = installedSize;
publishProgress(progress);
if (installedSize > prevInstalledSize + MIN_PROGRESS_TO_PUBLISH) {
publishProgress(installedSize);
prevInstalledSize = installedSize;
}
}