DSU service: Log insufficient storage space error
Log a specialized error message if installation task
failed due to insufficient storage space.
This helps the user to disgnose the source of error.
Bug: 200002443
Test: start DSU task and check logcat
Change-Id: Iabb3e0325ae99c343978ca6c35ab8378f20e0527
diff --git a/core/java/android/os/image/DynamicSystemManager.java b/core/java/android/os/image/DynamicSystemManager.java
index e8e4785..9610b16 100644
--- a/core/java/android/os/image/DynamicSystemManager.java
+++ b/core/java/android/os/image/DynamicSystemManager.java
@@ -16,13 +16,16 @@
package android.os.image;
+import android.annotation.NonNull;
import android.annotation.RequiresPermission;
import android.annotation.SystemService;
import android.content.Context;
import android.gsi.AvbPublicKey;
import android.gsi.GsiProgress;
+import android.gsi.IGsiService;
import android.os.ParcelFileDescriptor;
import android.os.RemoteException;
+import android.util.Pair;
/**
* The DynamicSystemManager offers a mechanism to use a new system image temporarily. After the
@@ -138,17 +141,18 @@
* @param name The DSU partition name
* @param size Size of the DSU image in bytes
* @param readOnly True if the partition is read only, e.g. system.
- * @return {@code true} if the call succeeds. {@code false} either the device does not contain
- * enough space or a DynamicSystem is currently in use where the {@link #isInUse} would be
- * true.
+ * @return {@code Integer} an IGsiService.INSTALL_* status code. {@link Session} an installation
+ * session object if successful, otherwise {@code null}.
*/
@RequiresPermission(android.Manifest.permission.MANAGE_DYNAMIC_SYSTEM)
- public Session createPartition(String name, long size, boolean readOnly) {
+ public @NonNull Pair<Integer, Session> createPartition(
+ String name, long size, boolean readOnly) {
try {
- if (mService.createPartition(name, size, readOnly)) {
- return new Session();
+ int status = mService.createPartition(name, size, readOnly);
+ if (status == IGsiService.INSTALL_OK) {
+ return new Pair<>(status, new Session());
} else {
- return null;
+ return new Pair<>(status, null);
}
} catch (RemoteException e) {
throw new RuntimeException(e.toString());
diff --git a/core/java/android/os/image/IDynamicSystemService.aidl b/core/java/android/os/image/IDynamicSystemService.aidl
index 4e69952..755368a 100644
--- a/core/java/android/os/image/IDynamicSystemService.aidl
+++ b/core/java/android/os/image/IDynamicSystemService.aidl
@@ -35,10 +35,10 @@
* @param name The DSU partition name
* @param size Size of the DSU image in bytes
* @param readOnly True if this partition is readOnly
- * @return true if the call succeeds
+ * @return IGsiService.INSTALL_* status code
*/
@EnforcePermission("MANAGE_DYNAMIC_SYSTEM")
- boolean createPartition(@utf8InCpp String name, long size, boolean readOnly);
+ int createPartition(@utf8InCpp String name, long size, boolean readOnly);
/**
* Complete the current partition installation.
diff --git a/packages/DynamicSystemInstallationService/src/com/android/dynsystem/DynamicSystemInstallationService.java b/packages/DynamicSystemInstallationService/src/com/android/dynsystem/DynamicSystemInstallationService.java
index 3a35659..5562684 100644
--- a/packages/DynamicSystemInstallationService/src/com/android/dynsystem/DynamicSystemInstallationService.java
+++ b/packages/DynamicSystemInstallationService/src/com/android/dynsystem/DynamicSystemInstallationService.java
@@ -110,6 +110,7 @@
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;
+ private static final int EVENT_DSU_INSTALL_INSUFFICIENT_SPACE = 120003;
protected static void logEventProgressUpdate(
String partitionName,
@@ -136,6 +137,10 @@
EventLog.writeEvent(EVENT_DSU_INSTALL_FAILED, cause);
}
+ protected static void logEventInsufficientSpace() {
+ EventLog.writeEvent(EVENT_DSU_INSTALL_INSUFFICIENT_SPACE);
+ }
+
/*
* IPC
*/
@@ -258,6 +263,8 @@
if (result == RESULT_CANCELLED) {
logEventFailed("Dynamic System installation task is canceled by the user.");
+ } else if (detail instanceof InstallationAsyncTask.InsufficientSpaceException) {
+ logEventInsufficientSpace();
} else {
logEventFailed("error: " + detail);
}
diff --git a/packages/DynamicSystemInstallationService/src/com/android/dynsystem/EventLogTags.logtags b/packages/DynamicSystemInstallationService/src/com/android/dynsystem/EventLogTags.logtags
index 4073143..8d8be10 100644
--- a/packages/DynamicSystemInstallationService/src/com/android/dynsystem/EventLogTags.logtags
+++ b/packages/DynamicSystemInstallationService/src/com/android/dynsystem/EventLogTags.logtags
@@ -5,3 +5,4 @@
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
120002 dsu_install_failed (cause|3)
+120003 dsu_install_insufficient_space
diff --git a/packages/DynamicSystemInstallationService/src/com/android/dynsystem/InstallationAsyncTask.java b/packages/DynamicSystemInstallationService/src/com/android/dynsystem/InstallationAsyncTask.java
index 38d851e..62e53d6 100644
--- a/packages/DynamicSystemInstallationService/src/com/android/dynsystem/InstallationAsyncTask.java
+++ b/packages/DynamicSystemInstallationService/src/com/android/dynsystem/InstallationAsyncTask.java
@@ -18,6 +18,7 @@
import android.content.Context;
import android.gsi.AvbPublicKey;
+import android.gsi.IGsiService;
import android.net.Uri;
import android.os.AsyncTask;
import android.os.Build;
@@ -27,6 +28,7 @@
import android.os.image.DynamicSystemManager;
import android.service.persistentdata.PersistentDataBlockManager;
import android.util.Log;
+import android.util.Pair;
import android.util.Range;
import android.webkit.URLUtil;
@@ -106,8 +108,15 @@
}
}
+ static class InsufficientSpaceException extends IOException {
+ InsufficientSpaceException(String message) {
+ super(message);
+ }
+ }
+
/** UNSET means the installation is not completed */
static final int RESULT_UNSET = 0;
+
static final int RESULT_OK = 1;
static final int RESULT_CANCELLED = 2;
static final int RESULT_ERROR_IO = 3;
@@ -157,6 +166,7 @@
private final boolean mIsNetworkUrl;
private final boolean mIsDeviceBootloaderUnlocked;
private final boolean mWantScratchPartition;
+ private int mCreatePartitionStatus;
private DynamicSystemManager.Session mInstallationSession;
private KeyRevocationList mKeyRevocationList;
@@ -364,7 +374,7 @@
mIsZip = true;
} else {
throw new UnsupportedFormatException(
- String.format(Locale.US, "Unsupported file format: %s", mUrl));
+ String.format(Locale.US, "Unsupported file format: %s", mUrl));
}
if (mIsNetworkUrl) {
@@ -435,14 +445,19 @@
throws IOException {
Log.d(TAG, "Creating writable partition: " + partitionName + ", size: " + partitionSize);
- Thread thread = new Thread() {
- @Override
- public void run() {
- mInstallationSession =
- mDynSystem.createPartition(
- partitionName, partitionSize, /* readOnly= */ false);
- }
- };
+ mCreatePartitionStatus = 0;
+ mInstallationSession = null;
+ Thread thread =
+ new Thread() {
+ @Override
+ public void run() {
+ Pair<Integer, DynamicSystemManager.Session> result =
+ mDynSystem.createPartition(
+ partitionName, partitionSize, /* readOnly = */ false);
+ mCreatePartitionStatus = result.first;
+ mInstallationSession = result.second;
+ }
+ };
initPartitionProgress(partitionName, partitionSize, /* readonly = */ false);
publishProgress(/* installedSize = */ 0L);
@@ -468,13 +483,17 @@
}
}
- if (prevInstalledSize != partitionSize) {
- publishProgress(partitionSize);
- }
-
if (mInstallationSession == null) {
- throw new IOException(
- "Failed to start installation with requested size: " + partitionSize);
+ if (mCreatePartitionStatus == IGsiService.INSTALL_ERROR_NO_SPACE
+ || mCreatePartitionStatus == IGsiService.INSTALL_ERROR_FILE_SYSTEM_CLUTTERED) {
+ throw new InsufficientSpaceException(
+ "Failed to create "
+ + partitionName
+ + " partition: storage media has insufficient free space");
+ } else {
+ throw new IOException(
+ "Failed to start installation with requested size: " + partitionSize);
+ }
}
// Reset installation session and verify that installation completes successfully.
@@ -482,6 +501,11 @@
if (!mDynSystem.closePartition()) {
throw new IOException("Failed to complete partition installation: " + partitionName);
}
+
+ // Ensure a 100% mark is published.
+ if (prevInstalledSize != partitionSize) {
+ publishProgress(partitionSize);
+ }
}
private void installScratch() throws IOException {
@@ -606,10 +630,19 @@
throw new IOException("Cannot get raw size for " + partitionName);
}
- Thread thread = new Thread(() -> {
- mInstallationSession =
- mDynSystem.createPartition(partitionName, partitionSize, true);
- });
+ mCreatePartitionStatus = 0;
+ mInstallationSession = null;
+ Thread thread =
+ new Thread() {
+ @Override
+ public void run() {
+ Pair<Integer, DynamicSystemManager.Session> result =
+ mDynSystem.createPartition(
+ partitionName, partitionSize, /* readOnly = */ true);
+ mCreatePartitionStatus = result.first;
+ mInstallationSession = result.second;
+ }
+ };
Log.d(TAG, "Start creating partition: " + partitionName);
thread.start();
@@ -627,8 +660,16 @@
}
if (mInstallationSession == null) {
- throw new IOException(
- "Failed to start installation with requested size: " + partitionSize);
+ if (mCreatePartitionStatus == IGsiService.INSTALL_ERROR_NO_SPACE
+ || mCreatePartitionStatus == IGsiService.INSTALL_ERROR_FILE_SYSTEM_CLUTTERED) {
+ throw new InsufficientSpaceException(
+ "Failed to create "
+ + partitionName
+ + " partition: storage media has insufficient free space");
+ } else {
+ throw new IOException(
+ "Failed to start installation with requested size: " + partitionSize);
+ }
}
Log.d(TAG, "Start installing: " + partitionName);
@@ -688,11 +729,6 @@
installedSize += numBytesRead;
}
- // Ensure a 100% mark is published.
- if (prevInstalledSize != partitionSize) {
- publishProgress(partitionSize);
- }
-
AvbPublicKey avbPublicKey = new AvbPublicKey();
if (!mInstallationSession.getAvbPublicKey(avbPublicKey)) {
imageValidationThrowOrWarning(new PublicKeyException("getAvbPublicKey() failed"));
@@ -708,6 +744,11 @@
if (!mDynSystem.closePartition()) {
throw new IOException("Failed to complete partition installation: " + partitionName);
}
+
+ // Ensure a 100% mark is published.
+ if (prevInstalledSize != partitionSize) {
+ publishProgress(partitionSize);
+ }
}
private static String toHexString(byte[] bytes) {
diff --git a/services/core/java/com/android/server/DynamicSystemService.java b/services/core/java/com/android/server/DynamicSystemService.java
index e924012..99e12a8 100644
--- a/services/core/java/com/android/server/DynamicSystemService.java
+++ b/services/core/java/com/android/server/DynamicSystemService.java
@@ -119,14 +119,13 @@
@Override
@EnforcePermission(android.Manifest.permission.MANAGE_DYNAMIC_SYSTEM)
- public boolean createPartition(String name, long size, boolean readOnly)
- throws RemoteException {
+ public int createPartition(String name, long size, boolean readOnly) throws RemoteException {
IGsiService service = getGsiService();
- if (service.createPartition(name, size, readOnly) != 0) {
- Slog.i(TAG, "Failed to install " + name);
- return false;
+ int status = service.createPartition(name, size, readOnly);
+ if (status != IGsiService.INSTALL_OK) {
+ Slog.i(TAG, "Failed to create partition: " + name);
}
- return true;
+ return status;
}
@Override