Merge "DSU service: Log insufficient storage space error" am: 9b420e664a am: 1e43855f6c

Original change: https://android-review.googlesource.com/c/platform/frameworks/base/+/2049806

Change-Id: I7b12a1c5d2dfb833c5330c44a35b110fc18c1859
Signed-off-by: Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
This commit is contained in:
Yi-yo Chiang
2022-04-01 08:29:33 +00:00
committed by Automerger Merge Worker
6 changed files with 93 additions and 41 deletions

View File

@@ -16,13 +16,16 @@
package android.os.image; package android.os.image;
import android.annotation.NonNull;
import android.annotation.RequiresPermission; import android.annotation.RequiresPermission;
import android.annotation.SystemService; import android.annotation.SystemService;
import android.content.Context; import android.content.Context;
import android.gsi.AvbPublicKey; import android.gsi.AvbPublicKey;
import android.gsi.GsiProgress; import android.gsi.GsiProgress;
import android.gsi.IGsiService;
import android.os.ParcelFileDescriptor; import android.os.ParcelFileDescriptor;
import android.os.RemoteException; import android.os.RemoteException;
import android.util.Pair;
/** /**
* The DynamicSystemManager offers a mechanism to use a new system image temporarily. After the * The DynamicSystemManager offers a mechanism to use a new system image temporarily. After the
@@ -138,17 +141,18 @@ public class DynamicSystemManager {
* @param name The DSU partition name * @param name The DSU partition name
* @param size Size of the DSU image in bytes * @param size Size of the DSU image in bytes
* @param readOnly True if the partition is read only, e.g. system. * @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 * @return {@code Integer} an IGsiService.INSTALL_* status code. {@link Session} an installation
* enough space or a DynamicSystem is currently in use where the {@link #isInUse} would be * session object if successful, otherwise {@code null}.
* true.
*/ */
@RequiresPermission(android.Manifest.permission.MANAGE_DYNAMIC_SYSTEM) @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 { try {
if (mService.createPartition(name, size, readOnly)) { int status = mService.createPartition(name, size, readOnly);
return new Session(); if (status == IGsiService.INSTALL_OK) {
return new Pair<>(status, new Session());
} else { } else {
return null; return new Pair<>(status, null);
} }
} catch (RemoteException e) { } catch (RemoteException e) {
throw new RuntimeException(e.toString()); throw new RuntimeException(e.toString());

View File

@@ -35,10 +35,10 @@ interface IDynamicSystemService
* @param name The DSU partition name * @param name The DSU partition name
* @param size Size of the DSU image in bytes * @param size Size of the DSU image in bytes
* @param readOnly True if this partition is readOnly * @param readOnly True if this partition is readOnly
* @return true if the call succeeds * @return IGsiService.INSTALL_* status code
*/ */
@EnforcePermission("MANAGE_DYNAMIC_SYSTEM") @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. * Complete the current partition installation.

View File

@@ -110,6 +110,7 @@ public class DynamicSystemInstallationService extends Service
private static final int EVENT_DSU_PROGRESS_UPDATE = 120000; 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_COMPLETE = 120001;
private static final int EVENT_DSU_INSTALL_FAILED = 120002; private static final int EVENT_DSU_INSTALL_FAILED = 120002;
private static final int EVENT_DSU_INSTALL_INSUFFICIENT_SPACE = 120003;
protected static void logEventProgressUpdate( protected static void logEventProgressUpdate(
String partitionName, String partitionName,
@@ -136,6 +137,10 @@ public class DynamicSystemInstallationService extends Service
EventLog.writeEvent(EVENT_DSU_INSTALL_FAILED, cause); EventLog.writeEvent(EVENT_DSU_INSTALL_FAILED, cause);
} }
protected static void logEventInsufficientSpace() {
EventLog.writeEvent(EVENT_DSU_INSTALL_INSUFFICIENT_SPACE);
}
/* /*
* IPC * IPC
*/ */
@@ -258,6 +263,8 @@ public class DynamicSystemInstallationService extends Service
if (result == RESULT_CANCELLED) { if (result == RESULT_CANCELLED) {
logEventFailed("Dynamic System installation task is canceled by the user."); logEventFailed("Dynamic System installation task is canceled by the user.");
} else if (detail instanceof InstallationAsyncTask.InsufficientSpaceException) {
logEventInsufficientSpace();
} else { } else {
logEventFailed("error: " + detail); logEventFailed("error: " + detail);
} }

View File

@@ -5,3 +5,4 @@ option java_package com.android.dynsystem
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) 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)
120003 dsu_install_insufficient_space

View File

@@ -18,6 +18,7 @@ package com.android.dynsystem;
import android.content.Context; import android.content.Context;
import android.gsi.AvbPublicKey; import android.gsi.AvbPublicKey;
import android.gsi.IGsiService;
import android.net.Uri; import android.net.Uri;
import android.os.AsyncTask; import android.os.AsyncTask;
import android.os.Build; import android.os.Build;
@@ -27,6 +28,7 @@ import android.os.SystemProperties;
import android.os.image.DynamicSystemManager; import android.os.image.DynamicSystemManager;
import android.service.persistentdata.PersistentDataBlockManager; import android.service.persistentdata.PersistentDataBlockManager;
import android.util.Log; import android.util.Log;
import android.util.Pair;
import android.util.Range; import android.util.Range;
import android.webkit.URLUtil; import android.webkit.URLUtil;
@@ -106,8 +108,15 @@ class InstallationAsyncTask extends AsyncTask<String, Long, Throwable> {
} }
} }
static class InsufficientSpaceException extends IOException {
InsufficientSpaceException(String message) {
super(message);
}
}
/** UNSET means the installation is not completed */ /** UNSET means the installation is not completed */
static final int RESULT_UNSET = 0; static final int RESULT_UNSET = 0;
static final int RESULT_OK = 1; static final int RESULT_OK = 1;
static final int RESULT_CANCELLED = 2; static final int RESULT_CANCELLED = 2;
static final int RESULT_ERROR_IO = 3; static final int RESULT_ERROR_IO = 3;
@@ -157,6 +166,7 @@ class InstallationAsyncTask extends AsyncTask<String, Long, Throwable> {
private final boolean mIsNetworkUrl; private final boolean mIsNetworkUrl;
private final boolean mIsDeviceBootloaderUnlocked; private final boolean mIsDeviceBootloaderUnlocked;
private final boolean mWantScratchPartition; private final boolean mWantScratchPartition;
private int mCreatePartitionStatus;
private DynamicSystemManager.Session mInstallationSession; private DynamicSystemManager.Session mInstallationSession;
private KeyRevocationList mKeyRevocationList; private KeyRevocationList mKeyRevocationList;
@@ -364,7 +374,7 @@ class InstallationAsyncTask extends AsyncTask<String, Long, Throwable> {
mIsZip = true; mIsZip = true;
} else { } else {
throw new UnsupportedFormatException( throw new UnsupportedFormatException(
String.format(Locale.US, "Unsupported file format: %s", mUrl)); String.format(Locale.US, "Unsupported file format: %s", mUrl));
} }
if (mIsNetworkUrl) { if (mIsNetworkUrl) {
@@ -435,14 +445,19 @@ class InstallationAsyncTask extends AsyncTask<String, Long, Throwable> {
throws IOException { throws IOException {
Log.d(TAG, "Creating writable partition: " + partitionName + ", size: " + partitionSize); Log.d(TAG, "Creating writable partition: " + partitionName + ", size: " + partitionSize);
Thread thread = new Thread() { mCreatePartitionStatus = 0;
@Override mInstallationSession = null;
public void run() { Thread thread =
mInstallationSession = new Thread() {
mDynSystem.createPartition( @Override
partitionName, partitionSize, /* readOnly= */ false); 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); initPartitionProgress(partitionName, partitionSize, /* readonly = */ false);
publishProgress(/* installedSize = */ 0L); publishProgress(/* installedSize = */ 0L);
@@ -468,13 +483,17 @@ class InstallationAsyncTask extends AsyncTask<String, Long, Throwable> {
} }
} }
if (prevInstalledSize != partitionSize) {
publishProgress(partitionSize);
}
if (mInstallationSession == null) { if (mInstallationSession == null) {
throw new IOException( if (mCreatePartitionStatus == IGsiService.INSTALL_ERROR_NO_SPACE
"Failed to start installation with requested size: " + partitionSize); || 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. // Reset installation session and verify that installation completes successfully.
@@ -482,6 +501,11 @@ class InstallationAsyncTask extends AsyncTask<String, Long, Throwable> {
if (!mDynSystem.closePartition()) { if (!mDynSystem.closePartition()) {
throw new IOException("Failed to complete partition installation: " + partitionName); 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 { private void installScratch() throws IOException {
@@ -606,10 +630,19 @@ class InstallationAsyncTask extends AsyncTask<String, Long, Throwable> {
throw new IOException("Cannot get raw size for " + partitionName); throw new IOException("Cannot get raw size for " + partitionName);
} }
Thread thread = new Thread(() -> { mCreatePartitionStatus = 0;
mInstallationSession = mInstallationSession = null;
mDynSystem.createPartition(partitionName, partitionSize, true); 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); Log.d(TAG, "Start creating partition: " + partitionName);
thread.start(); thread.start();
@@ -627,8 +660,16 @@ class InstallationAsyncTask extends AsyncTask<String, Long, Throwable> {
} }
if (mInstallationSession == null) { if (mInstallationSession == null) {
throw new IOException( if (mCreatePartitionStatus == IGsiService.INSTALL_ERROR_NO_SPACE
"Failed to start installation with requested size: " + partitionSize); || 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); Log.d(TAG, "Start installing: " + partitionName);
@@ -688,11 +729,6 @@ class InstallationAsyncTask extends AsyncTask<String, Long, Throwable> {
installedSize += numBytesRead; installedSize += numBytesRead;
} }
// Ensure a 100% mark is published.
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"));
@@ -708,6 +744,11 @@ class InstallationAsyncTask extends AsyncTask<String, Long, Throwable> {
if (!mDynSystem.closePartition()) { if (!mDynSystem.closePartition()) {
throw new IOException("Failed to complete partition installation: " + partitionName); 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) { private static String toHexString(byte[] bytes) {

View File

@@ -119,14 +119,13 @@ public class DynamicSystemService extends IDynamicSystemService.Stub {
@Override @Override
@EnforcePermission(android.Manifest.permission.MANAGE_DYNAMIC_SYSTEM) @EnforcePermission(android.Manifest.permission.MANAGE_DYNAMIC_SYSTEM)
public boolean createPartition(String name, long size, boolean readOnly) public int createPartition(String name, long size, boolean readOnly) throws RemoteException {
throws RemoteException {
IGsiService service = getGsiService(); IGsiService service = getGsiService();
if (service.createPartition(name, size, readOnly) != 0) { int status = service.createPartition(name, size, readOnly);
Slog.i(TAG, "Failed to install " + name); if (status != IGsiService.INSTALL_OK) {
return false; Slog.i(TAG, "Failed to create partition: " + name);
} }
return true; return status;
} }
@Override @Override