Merge "DSU installation service: Add event log tags"
This commit is contained in:
@@ -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"],
|
||||
}
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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)
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user