Pass exception detail to API user
Per API review, DynamicSystem installation service will also pass
exceptions to users of DynamicSystemClient.
Bug: 126613281
Test: build and run, verified with test app.
Change-Id: I413d6137837eaa968f59550f110da34cea66d4d4
diff --git a/api/system-current.txt b/api/system-current.txt
index 32ddab9..df1eab3 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -5660,7 +5660,7 @@
}
public static interface DynamicSystemClient.OnStatusChangedListener {
- method public void onStatusChanged(int, int, long);
+ method public void onStatusChanged(int, int, long, @Nullable Throwable);
}
}
diff --git a/core/java/android/os/image/DynamicSystemClient.java b/core/java/android/os/image/DynamicSystemClient.java
index 33a6ee8..87367ac 100644
--- a/core/java/android/os/image/DynamicSystemClient.java
+++ b/core/java/android/os/image/DynamicSystemClient.java
@@ -19,6 +19,7 @@
import android.annotation.CallbackExecutor;
import android.annotation.IntDef;
import android.annotation.NonNull;
+import android.annotation.Nullable;
import android.annotation.RequiresPermission;
import android.annotation.SystemApi;
import android.content.ComponentName;
@@ -31,6 +32,7 @@
import android.os.Looper;
import android.os.Message;
import android.os.Messenger;
+import android.os.ParcelableException;
import android.os.RemoteException;
import android.util.Slog;
@@ -100,9 +102,10 @@
* @param status status code, also defined in {@code DynamicSystemClient}.
* @param cause cause code, also defined in {@code DynamicSystemClient}.
* @param progress number of bytes installed.
+ * @param detail additional detail about the error if available, otherwise null.
*/
void onStatusChanged(@InstallationStatus int status, @StatusChangedCause int cause,
- @BytesLong long progress);
+ @BytesLong long progress, @Nullable Throwable detail);
}
/*
@@ -177,6 +180,12 @@
*/
public static final String KEY_INSTALLED_SIZE = "KEY_INSTALLED_SIZE";
+ /**
+ * Message key, used when the service is sending exception detail to the client.
+ * @hide
+ */
+ public static final String KEY_EXCEPTION_DETAIL = "KEY_EXCEPTION_DETAIL";
+
/*
* Intent Actions
*/
@@ -248,7 +257,7 @@
} catch (RemoteException e) {
Slog.e(TAG, "Unable to get status from installation service");
mExecutor.execute(() -> {
- mListener.onStatusChanged(STATUS_UNKNOWN, CAUSE_ERROR_IPC, 0);
+ mListener.onStatusChanged(STATUS_UNKNOWN, CAUSE_ERROR_IPC, 0, e);
});
}
}
@@ -396,14 +405,19 @@
int status = msg.arg1;
int cause = msg.arg2;
// obj is non-null
- long progress = ((Bundle) msg.obj).getLong(KEY_INSTALLED_SIZE);
+ Bundle bundle = (Bundle) msg.obj;
+ long progress = bundle.getLong(KEY_INSTALLED_SIZE);
+ ParcelableException t = (ParcelableException) bundle.getSerializable(
+ KEY_EXCEPTION_DETAIL);
+
+ Throwable detail = t == null ? null : t.getCause();
if (mExecutor != null) {
mExecutor.execute(() -> {
- mListener.onStatusChanged(status, cause, progress);
+ mListener.onStatusChanged(status, cause, progress, detail);
});
} else {
- mListener.onStatusChanged(status, cause, progress);
+ mListener.onStatusChanged(status, cause, progress, detail);
}
break;
default:
diff --git a/packages/DynamicSystemInstallationService/src/com/android/dynandroid/DynamicSystemInstallationService.java b/packages/DynamicSystemInstallationService/src/com/android/dynandroid/DynamicSystemInstallationService.java
index df2c571..e479e38 100644
--- a/packages/DynamicSystemInstallationService/src/com/android/dynandroid/DynamicSystemInstallationService.java
+++ b/packages/DynamicSystemInstallationService/src/com/android/dynandroid/DynamicSystemInstallationService.java
@@ -49,6 +49,7 @@
import android.os.IBinder;
import android.os.Message;
import android.os.Messenger;
+import android.os.ParcelableException;
import android.os.PowerManager;
import android.os.RemoteException;
import android.os.image.DynamicSystemClient;
@@ -170,13 +171,13 @@
@Override
public void onProgressUpdate(long installedSize) {
mInstalledSize = installedSize;
- postStatus(STATUS_IN_PROGRESS, CAUSE_NOT_SPECIFIED);
+ postStatus(STATUS_IN_PROGRESS, CAUSE_NOT_SPECIFIED, null);
}
@Override
- public void onResult(int result) {
+ public void onResult(int result, Throwable detail) {
if (result == RESULT_OK) {
- postStatus(STATUS_READY, CAUSE_INSTALL_COMPLETED);
+ postStatus(STATUS_READY, CAUSE_INSTALL_COMPLETED, null);
return;
}
@@ -185,15 +186,15 @@
switch (result) {
case RESULT_ERROR_IO:
- postStatus(STATUS_NOT_STARTED, CAUSE_ERROR_IO);
+ postStatus(STATUS_NOT_STARTED, CAUSE_ERROR_IO, detail);
break;
case RESULT_ERROR_INVALID_URL:
- postStatus(STATUS_NOT_STARTED, CAUSE_ERROR_INVALID_URL);
+ postStatus(STATUS_NOT_STARTED, CAUSE_ERROR_INVALID_URL, detail);
break;
case RESULT_ERROR_EXCEPTION:
- postStatus(STATUS_NOT_STARTED, CAUSE_ERROR_EXCEPTION);
+ postStatus(STATUS_NOT_STARTED, CAUSE_ERROR_EXCEPTION, detail);
break;
}
}
@@ -201,7 +202,7 @@
@Override
public void onCancelled() {
resetTaskAndStop();
- postStatus(STATUS_NOT_STARTED, CAUSE_INSTALL_CANCELLED);
+ postStatus(STATUS_NOT_STARTED, CAUSE_INSTALL_CANCELLED, null);
}
private void executeInstallCommand(Intent intent) {
@@ -266,7 +267,7 @@
Toast.LENGTH_LONG).show();
resetTaskAndStop();
- postStatus(STATUS_NOT_STARTED, CAUSE_INSTALL_CANCELLED);
+ postStatus(STATUS_NOT_STARTED, CAUSE_INSTALL_CANCELLED, null);
mDynSystem.remove();
}
@@ -414,7 +415,7 @@
return VerificationActivity.isVerified(url);
}
- private void postStatus(int status, int cause) {
+ private void postStatus(int status, int cause, Throwable detail) {
Log.d(TAG, "postStatus(): statusCode=" + status + ", causeCode=" + cause);
boolean notifyOnNotificationBar = true;
@@ -433,18 +434,24 @@
for (int i = mClients.size() - 1; i >= 0; i--) {
try {
- notifyOneClient(mClients.get(i), status, cause);
+ notifyOneClient(mClients.get(i), status, cause, detail);
} catch (RemoteException e) {
mClients.remove(i);
}
}
}
- private void notifyOneClient(Messenger client, int status, int cause) throws RemoteException {
+ private void notifyOneClient(Messenger client, int status, int cause, Throwable detail)
+ throws RemoteException {
Bundle bundle = new Bundle();
bundle.putLong(DynamicSystemClient.KEY_INSTALLED_SIZE, mInstalledSize);
+ if (detail != null) {
+ bundle.putSerializable(DynamicSystemClient.KEY_EXCEPTION_DETAIL,
+ new ParcelableException(detail));
+ }
+
client.send(Message.obtain(null,
DynamicSystemClient.MSG_POST_STATUS, status, cause, bundle));
}
@@ -496,7 +503,7 @@
int status = getStatus();
// tell just registered client my status, but do not specify cause
- notifyOneClient(client, status, CAUSE_NOT_SPECIFIED);
+ notifyOneClient(client, status, CAUSE_NOT_SPECIFIED, null);
mClients.add(client);
} catch (RemoteException e) {
diff --git a/packages/DynamicSystemInstallationService/src/com/android/dynandroid/InstallationAsyncTask.java b/packages/DynamicSystemInstallationService/src/com/android/dynandroid/InstallationAsyncTask.java
index 052fc0a..aee5de5 100644
--- a/packages/DynamicSystemInstallationService/src/com/android/dynandroid/InstallationAsyncTask.java
+++ b/packages/DynamicSystemInstallationService/src/com/android/dynandroid/InstallationAsyncTask.java
@@ -31,7 +31,7 @@
import java.util.zip.GZIPInputStream;
-class InstallationAsyncTask extends AsyncTask<String, Long, Integer> {
+class InstallationAsyncTask extends AsyncTask<String, Long, Throwable> {
private static final String TAG = "InstallationAsyncTask";
@@ -43,7 +43,6 @@
}
}
-
/** Not completed, including being cancelled */
static final int NO_RESULT = 0;
static final int RESULT_OK = 1;
@@ -53,7 +52,7 @@
interface InstallStatusListener {
void onProgressUpdate(long installedSize);
- void onResult(int resultCode);
+ void onResult(int resultCode, Throwable detail);
void onCancelled();
}
@@ -84,7 +83,7 @@
}
@Override
- protected Integer doInBackground(String... voids) {
+ protected Throwable doInBackground(String... voids) {
Log.d(TAG, "Start doInBackground(), URL: " + mUrl);
try {
@@ -108,7 +107,7 @@
if (isCancelled()) {
boolean aborted = mDynSystem.abort();
Log.d(TAG, "Called DynamicSystemManager.abort(), result = " + aborted);
- return RESULT_OK;
+ return null;
}
GsiProgress progress = mDynSystem.getInstallationProgress();
@@ -124,10 +123,8 @@
if (mInstallationSession == null) {
- Log.e(TAG, "Failed to start installation with requested size: "
+ throw new IOException("Failed to start installation with requested size: "
+ (mSystemSize + mUserdataSize));
-
- return RESULT_ERROR_IO;
}
installedSize = mUserdataSize;
@@ -157,20 +154,11 @@
}
}
- return RESULT_OK;
-
- } catch (IOException e) {
- e.printStackTrace();
- return RESULT_ERROR_IO;
-
- } catch (InvalidImageUrlException e) {
- e.printStackTrace();
- return RESULT_ERROR_INVALID_URL;
+ return null;
} catch (Exception e) {
e.printStackTrace();
- return RESULT_ERROR_EXCEPTION;
-
+ return e;
} finally {
close();
}
@@ -180,19 +168,24 @@
protected void onCancelled() {
Log.d(TAG, "onCancelled(), URL: " + mUrl);
- close();
-
mListener.onCancelled();
}
@Override
- protected void onPostExecute(Integer result) {
- Log.d(TAG, "onPostExecute(), URL: " + mUrl + ", result: " + result);
+ protected void onPostExecute(Throwable detail) {
+ if (detail == null) {
+ mResult = RESULT_OK;
+ } else if (detail instanceof IOException) {
+ mResult = RESULT_ERROR_IO;
+ } else if (detail instanceof InvalidImageUrlException) {
+ mResult = RESULT_ERROR_INVALID_URL;
+ } else {
+ mResult = RESULT_ERROR_EXCEPTION;
+ }
- close();
+ Log.d(TAG, "onPostExecute(), URL: " + mUrl + ", result: " + mResult);
- mResult = result;
- mListener.onResult(mResult);
+ mListener.onResult(mResult, detail);
}
@Override