summaryrefslogtreecommitdiff
path: root/packages/DynamicSystemInstallationService/src
diff options
context:
space:
mode:
authorPo-Chien Hsueh <pchsueh@google.com>2019-10-30 16:48:15 +0800
committerPo-Chien Hsueh <pchsueh@google.com>2019-11-22 15:12:22 +0800
commit99d18dddd27634c1e0085041989ab01489d97cda (patch)
tree37f4ca2aa1b156222126e64080229ac1e9cb1dce /packages/DynamicSystemInstallationService/src
parent265f8bfd99becca62c2bc0d1b2d0d8cc59ca77a9 (diff)
DSU to support zip files
DSU previously only supports gzipped system images. This CL enables DSU to also read zipped files. If there are multiple images in the zipped release, DSU will install them all. Bug: 134353973 Test: adb shell am start-activity \ -n com.android.dynsystem/com.android.dynsystem.VerificationActivity \ -a android.os.image.action.START_INSTALL \ -d https://dl.google.com/developers/android/qt/images/gsi/aosp_arm64-QP1A.190771.020-5800535.zip \ --el KEY_USERDATA_SIZE 8589934592 Test: adb shell am start-activity \ -n com.android.dynsystem/com.android.dynsystem.VerificationActivity \ -a android.os.image.action.START_INSTALL \ -d file:///storage/emulated/0/Download/aosp_crosshatch-img-eng.pchsueh.zip \ --el KEY_USERDATA_SIZE 8589934592 Change-Id: I9c2137d4d81398a9c6153df63a29c16eb8339795
Diffstat (limited to 'packages/DynamicSystemInstallationService/src')
-rw-r--r--packages/DynamicSystemInstallationService/src/com/android/dynsystem/DynamicSystemInstallationService.java67
-rw-r--r--packages/DynamicSystemInstallationService/src/com/android/dynsystem/InstallationAsyncTask.java418
2 files changed, 347 insertions, 138 deletions
diff --git a/packages/DynamicSystemInstallationService/src/com/android/dynsystem/DynamicSystemInstallationService.java b/packages/DynamicSystemInstallationService/src/com/android/dynsystem/DynamicSystemInstallationService.java
index 142078e1b77c..9e49826f70c3 100644
--- a/packages/DynamicSystemInstallationService/src/com/android/dynsystem/DynamicSystemInstallationService.java
+++ b/packages/DynamicSystemInstallationService/src/com/android/dynsystem/DynamicSystemInstallationService.java
@@ -32,9 +32,11 @@ import static android.os.image.DynamicSystemClient.STATUS_IN_USE;
import static android.os.image.DynamicSystemClient.STATUS_NOT_STARTED;
import static android.os.image.DynamicSystemClient.STATUS_READY;
+import static com.android.dynsystem.InstallationAsyncTask.RESULT_CANCELLED;
import static com.android.dynsystem.InstallationAsyncTask.RESULT_ERROR_EXCEPTION;
-import static com.android.dynsystem.InstallationAsyncTask.RESULT_ERROR_INVALID_URL;
import static com.android.dynsystem.InstallationAsyncTask.RESULT_ERROR_IO;
+import static com.android.dynsystem.InstallationAsyncTask.RESULT_ERROR_UNSUPPORTED_FORMAT;
+import static com.android.dynsystem.InstallationAsyncTask.RESULT_ERROR_UNSUPPORTED_URL;
import static com.android.dynsystem.InstallationAsyncTask.RESULT_OK;
import android.app.Notification;
@@ -66,11 +68,10 @@ import java.util.ArrayList;
* cancel and confirm commnands.
*/
public class DynamicSystemInstallationService extends Service
- implements InstallationAsyncTask.InstallStatusListener {
+ implements InstallationAsyncTask.ProgressListener {
private static final String TAG = "DynSystemInstallationService";
-
// TODO (b/131866826): This is currently for test only. Will move this to System API.
static final String KEY_ENABLE_WHEN_COMPLETED = "KEY_ENABLE_WHEN_COMPLETED";
@@ -121,9 +122,12 @@ public class DynamicSystemInstallationService extends Service
private DynamicSystemManager mDynSystem;
private NotificationManager mNM;
- private long mSystemSize;
- private long mUserdataSize;
- private long mInstalledSize;
+ private int mNumInstalledPartitions;
+
+ private String mCurrentPartitionName;
+ private long mCurrentPartitionSize;
+ private long mCurrentPartitionInstalledSize;
+
private boolean mJustCancelledByUser;
// This is for testing only now
@@ -176,8 +180,12 @@ public class DynamicSystemInstallationService extends Service
}
@Override
- public void onProgressUpdate(long installedSize) {
- mInstalledSize = installedSize;
+ public void onProgressUpdate(InstallationAsyncTask.Progress progress) {
+ mCurrentPartitionName = progress.mPartitionName;
+ mCurrentPartitionSize = progress.mPartitionSize;
+ mCurrentPartitionInstalledSize = progress.mInstalledSize;
+ mNumInstalledPartitions = progress.mNumInstalledPartitions;
+
postStatus(STATUS_IN_PROGRESS, CAUSE_NOT_SPECIFIED, null);
}
@@ -197,11 +205,16 @@ public class DynamicSystemInstallationService extends Service
resetTaskAndStop();
switch (result) {
+ case RESULT_CANCELLED:
+ postStatus(STATUS_NOT_STARTED, CAUSE_INSTALL_CANCELLED, null);
+ break;
+
case RESULT_ERROR_IO:
postStatus(STATUS_NOT_STARTED, CAUSE_ERROR_IO, detail);
break;
- case RESULT_ERROR_INVALID_URL:
+ case RESULT_ERROR_UNSUPPORTED_URL:
+ case RESULT_ERROR_UNSUPPORTED_FORMAT:
postStatus(STATUS_NOT_STARTED, CAUSE_ERROR_INVALID_URL, detail);
break;
@@ -211,12 +224,6 @@ public class DynamicSystemInstallationService extends Service
}
}
- @Override
- public void onCancelled() {
- resetTaskAndStop();
- postStatus(STATUS_NOT_STARTED, CAUSE_INSTALL_CANCELLED, null);
- }
-
private void executeInstallCommand(Intent intent) {
if (!verifyRequest(intent)) {
Log.e(TAG, "Verification failed. Did you use VerificationActivity?");
@@ -234,12 +241,13 @@ public class DynamicSystemInstallationService extends Service
}
String url = intent.getDataString();
- mSystemSize = intent.getLongExtra(DynamicSystemClient.KEY_SYSTEM_SIZE, 0);
- mUserdataSize = intent.getLongExtra(DynamicSystemClient.KEY_USERDATA_SIZE, 0);
+ long systemSize = intent.getLongExtra(DynamicSystemClient.KEY_SYSTEM_SIZE, 0);
+ long userdataSize = intent.getLongExtra(DynamicSystemClient.KEY_USERDATA_SIZE, 0);
mEnableWhenCompleted = intent.getBooleanExtra(KEY_ENABLE_WHEN_COMPLETED, false);
+ // TODO: better constructor or builder
mInstallTask = new InstallationAsyncTask(
- url, mSystemSize, mUserdataSize, this, mDynSystem, this);
+ url, systemSize, userdataSize, this, mDynSystem, this);
mInstallTask.execute();
@@ -257,7 +265,7 @@ public class DynamicSystemInstallationService extends Service
mJustCancelledByUser = true;
if (mInstallTask.cancel(false)) {
- // Will cleanup and post status in onCancelled()
+ // Will cleanup and post status in onResult()
Log.d(TAG, "Cancel request filed successfully");
} else {
Log.e(TAG, "Trying to cancel installation while it's already completed.");
@@ -288,7 +296,7 @@ public class DynamicSystemInstallationService extends Service
private void executeRebootToDynSystemCommand() {
boolean enabled = false;
- if (mInstallTask != null && mInstallTask.getResult() == RESULT_OK) {
+ if (mInstallTask != null && mInstallTask.isCompleted()) {
enabled = mInstallTask.commit();
} else if (isDynamicSystemInstalled()) {
enabled = mDynSystem.setEnable(true, true);
@@ -380,8 +388,16 @@ public class DynamicSystemInstallationService extends Service
case STATUS_IN_PROGRESS:
builder.setContentText(getString(R.string.notification_install_inprogress));
- int max = (int) Math.max((mSystemSize + mUserdataSize) >> 20, 1);
- int progress = (int) (mInstalledSize >> 20);
+ int max = 1024;
+ int progress = 0;
+
+ int currentMax = max >> (mNumInstalledPartitions + 1);
+ progress = max - currentMax * 2;
+
+ long currentProgress = (mCurrentPartitionInstalledSize >> 20) * currentMax
+ / Math.max(mCurrentPartitionSize >> 20, 1);
+
+ progress += (int) currentProgress;
builder.setProgress(max, progress, false);
@@ -464,7 +480,8 @@ public class DynamicSystemInstallationService extends Service
throws RemoteException {
Bundle bundle = new Bundle();
- bundle.putLong(DynamicSystemClient.KEY_INSTALLED_SIZE, mInstalledSize);
+ // TODO: send more info to the clients
+ bundle.putLong(DynamicSystemClient.KEY_INSTALLED_SIZE, mCurrentPartitionInstalledSize);
if (detail != null) {
bundle.putSerializable(DynamicSystemClient.KEY_EXCEPTION_DETAIL,
@@ -492,9 +509,7 @@ public class DynamicSystemInstallationService extends Service
return STATUS_IN_PROGRESS;
case FINISHED:
- int result = mInstallTask.getResult();
-
- if (result == RESULT_OK) {
+ if (mInstallTask.isCompleted()) {
return STATUS_READY;
} else {
throw new IllegalStateException("A failed InstallationTask is not reset");
diff --git a/packages/DynamicSystemInstallationService/src/com/android/dynsystem/InstallationAsyncTask.java b/packages/DynamicSystemInstallationService/src/com/android/dynsystem/InstallationAsyncTask.java
index 19ae97070188..b206a1fccba4 100644
--- a/packages/DynamicSystemInstallationService/src/com/android/dynsystem/InstallationAsyncTask.java
+++ b/packages/DynamicSystemInstallationService/src/com/android/dynsystem/InstallationAsyncTask.java
@@ -17,7 +17,6 @@
package com.android.dynsystem;
import android.content.Context;
-import android.gsi.GsiProgress;
import android.net.Uri;
import android.os.AsyncTask;
import android.os.MemoryFile;
@@ -27,35 +26,70 @@ import android.util.Log;
import android.webkit.URLUtil;
import java.io.BufferedInputStream;
+import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
+import java.util.Arrays;
+import java.util.Enumeration;
+import java.util.List;
import java.util.Locale;
import java.util.zip.GZIPInputStream;
+import java.util.zip.ZipEntry;
+import java.util.zip.ZipFile;
+import java.util.zip.ZipInputStream;
-class InstallationAsyncTask extends AsyncTask<String, Long, Throwable> {
+class InstallationAsyncTask extends AsyncTask<String, InstallationAsyncTask.Progress, Throwable> {
private static final String TAG = "InstallationAsyncTask";
private static final int READ_BUFFER_SIZE = 1 << 13;
+ private static final long MIN_PROGRESS_TO_PUBLISH = 1 << 27;
- private class InvalidImageUrlException extends RuntimeException {
- private InvalidImageUrlException(String message) {
+ private static final List<String> UNSUPPORTED_PARTITIONS =
+ Arrays.asList("vbmeta", "boot", "userdata", "dtbo", "super_empty", "system_other");
+
+ private class UnsupportedUrlException extends RuntimeException {
+ private UnsupportedUrlException(String message) {
+ super(message);
+ }
+ }
+
+ private class UnsupportedFormatException extends RuntimeException {
+ private UnsupportedFormatException(String message) {
super(message);
}
}
- /** Not completed, including being cancelled */
- static final int NO_RESULT = 0;
+ /** UNSET means the installation is not completed */
+ static final int RESULT_UNSET = 0;
static final int RESULT_OK = 1;
- static final int RESULT_ERROR_IO = 2;
- static final int RESULT_ERROR_INVALID_URL = 3;
+ static final int RESULT_CANCELLED = 2;
+ static final int RESULT_ERROR_IO = 3;
+ static final int RESULT_ERROR_UNSUPPORTED_URL = 4;
+ static final int RESULT_ERROR_UNSUPPORTED_FORMAT = 5;
static final int RESULT_ERROR_EXCEPTION = 6;
- interface InstallStatusListener {
- void onProgressUpdate(long installedSize);
+ class Progress {
+ String mPartitionName;
+ long mPartitionSize;
+ long mInstalledSize;
+
+ int mNumInstalledPartitions;
+
+ Progress(String partitionName, long partitionSize, long installedSize,
+ int numInstalled) {
+ mPartitionName = partitionName;
+ mPartitionSize = partitionSize;
+ mInstalledSize = installedSize;
+
+ mNumInstalledPartitions = numInstalled;
+ }
+ }
+
+ interface ProgressListener {
+ void onProgressUpdate(Progress progress);
void onResult(int resultCode, Throwable detail);
- void onCancelled();
}
private final String mUrl;
@@ -63,16 +97,17 @@ class InstallationAsyncTask extends AsyncTask<String, Long, Throwable> {
private final long mUserdataSize;
private final Context mContext;
private final DynamicSystemManager mDynSystem;
- private final InstallStatusListener mListener;
+ private final ProgressListener mListener;
private DynamicSystemManager.Session mInstallationSession;
- private int mResult = NO_RESULT;
+ private boolean mIsZip;
+ private boolean mIsCompleted;
private InputStream mStream;
-
+ private ZipFile mZipFile;
InstallationAsyncTask(String url, long systemSize, long userdataSize, Context context,
- DynamicSystemManager dynSystem, InstallStatusListener listener) {
+ DynamicSystemManager dynSystem, ProgressListener listener) {
mUrl = url;
mSystemSize = systemSize;
mUserdataSize = userdataSize;
@@ -82,133 +117,292 @@ class InstallationAsyncTask extends AsyncTask<String, Long, Throwable> {
}
@Override
- protected void onPreExecute() {
- mListener.onProgressUpdate(0);
- }
-
- @Override
protected Throwable doInBackground(String... voids) {
Log.d(TAG, "Start doInBackground(), URL: " + mUrl);
try {
- long installedSize = 0;
- long reportedInstalledSize = 0;
-
- long minStepToReport = (mSystemSize + mUserdataSize) / 100;
-
- // init input stream before calling startInstallation(), which takes 90 seconds.
- initInputStream();
+ // call DynamicSystemManager to cleanup stuff
+ mDynSystem.remove();
- Thread thread =
- new Thread(
- () -> {
- mDynSystem.startInstallation();
- mDynSystem.createPartition("userdata", mUserdataSize, false);
- mInstallationSession =
- mDynSystem.createPartition("system", mSystemSize, true);
- });
+ verifyAndPrepare();
- thread.start();
+ mDynSystem.startInstallation();
- while (thread.isAlive()) {
- if (isCancelled()) {
- boolean aborted = mDynSystem.abort();
- Log.d(TAG, "Called DynamicSystemManager.abort(), result = " + aborted);
- return null;
- }
-
- GsiProgress progress = mDynSystem.getInstallationProgress();
- installedSize = progress.bytes_processed;
-
- if (installedSize > reportedInstalledSize + minStepToReport) {
- publishProgress(installedSize);
- reportedInstalledSize = installedSize;
- }
-
- Thread.sleep(10);
+ installUserdata();
+ if (isCancelled()) {
+ mDynSystem.remove();
+ return null;
}
- if (mInstallationSession == null) {
- throw new IOException(
- "Failed to start installation with requested size: "
- + (mSystemSize + mUserdataSize));
+ installImages();
+ if (isCancelled()) {
+ mDynSystem.remove();
+ return null;
}
- installedSize = mUserdataSize;
-
- MemoryFile memoryFile = new MemoryFile("dsu", READ_BUFFER_SIZE);
- byte[] bytes = new byte[READ_BUFFER_SIZE];
- mInstallationSession.setAshmem(
- new ParcelFileDescriptor(memoryFile.getFileDescriptor()), READ_BUFFER_SIZE);
- int numBytesRead;
- Log.d(TAG, "Start installation loop");
- while ((numBytesRead = mStream.read(bytes, 0, READ_BUFFER_SIZE)) != -1) {
- memoryFile.writeBytes(bytes, 0, 0, numBytesRead);
- if (isCancelled()) {
- break;
- }
- if (!mInstallationSession.submitFromAshmem(numBytesRead)) {
- throw new IOException("Failed write() to DynamicSystem");
- }
-
- installedSize += numBytesRead;
-
- if (installedSize > reportedInstalledSize + minStepToReport) {
- publishProgress(installedSize);
- reportedInstalledSize = installedSize;
- }
- }
mDynSystem.finishInstallation();
- return null;
-
} catch (Exception e) {
e.printStackTrace();
+ mDynSystem.remove();
return e;
} finally {
close();
}
- }
-
- @Override
- protected void onCancelled() {
- Log.d(TAG, "onCancelled(), URL: " + mUrl);
- mListener.onCancelled();
+ return null;
}
@Override
protected void onPostExecute(Throwable detail) {
+ int result = RESULT_UNSET;
+
if (detail == null) {
- mResult = RESULT_OK;
+ result = RESULT_OK;
+ mIsCompleted = true;
} else if (detail instanceof IOException) {
- mResult = RESULT_ERROR_IO;
- } else if (detail instanceof InvalidImageUrlException) {
- mResult = RESULT_ERROR_INVALID_URL;
+ result = RESULT_ERROR_IO;
+ } else if (detail instanceof UnsupportedUrlException) {
+ result = RESULT_ERROR_UNSUPPORTED_URL;
+ } else if (detail instanceof UnsupportedFormatException) {
+ result = RESULT_ERROR_UNSUPPORTED_FORMAT;
} else {
- mResult = RESULT_ERROR_EXCEPTION;
+ result = RESULT_ERROR_EXCEPTION;
}
- Log.d(TAG, "onPostExecute(), URL: " + mUrl + ", result: " + mResult);
+ Log.d(TAG, "onPostExecute(), URL: " + mUrl + ", result: " + result);
+
+ mListener.onResult(result, detail);
+ }
+
+ @Override
+ protected void onCancelled() {
+ Log.d(TAG, "onCancelled(), URL: " + mUrl);
- mListener.onResult(mResult, detail);
+ if (mDynSystem.abort()) {
+ Log.d(TAG, "Installation aborted");
+ } else {
+ Log.w(TAG, "DynamicSystemManager.abort() returned false");
+ }
+
+ mListener.onResult(RESULT_CANCELLED, null);
}
@Override
- protected void onProgressUpdate(Long... values) {
- long progress = values[0];
+ protected void onProgressUpdate(Progress... values) {
+ Progress progress = values[0];
mListener.onProgressUpdate(progress);
}
- private void initInputStream() throws IOException, InvalidImageUrlException {
- if (URLUtil.isNetworkUrl(mUrl) || URLUtil.isFileUrl(mUrl)) {
- mStream = new BufferedInputStream(new GZIPInputStream(new URL(mUrl).openStream()));
+ private void verifyAndPrepare() throws Exception {
+ String extension = mUrl.substring(mUrl.lastIndexOf('.') + 1);
+
+ if ("gz".equals(extension) || "gzip".equals(extension)) {
+ mIsZip = false;
+ } else if ("zip".equals(extension)) {
+ mIsZip = true;
+ } else {
+ throw new UnsupportedFormatException(
+ String.format(Locale.US, "Unsupported file format: %s", mUrl));
+ }
+
+ if (URLUtil.isNetworkUrl(mUrl)) {
+ mStream = new URL(mUrl).openStream();
+ } else if (URLUtil.isFileUrl(mUrl)) {
+ if (mIsZip) {
+ mZipFile = new ZipFile(new File(new URL(mUrl).toURI()));
+ } else {
+ mStream = new URL(mUrl).openStream();
+ }
} else if (URLUtil.isContentUrl(mUrl)) {
- Uri uri = Uri.parse(mUrl);
- mStream = new BufferedInputStream(new GZIPInputStream(
- mContext.getContentResolver().openInputStream(uri)));
+ mStream = mContext.getContentResolver().openInputStream(Uri.parse(mUrl));
+ } else {
+ throw new UnsupportedUrlException(
+ String.format(Locale.US, "Unsupported URL: %s", mUrl));
+ }
+ }
+
+ private void installUserdata() throws Exception {
+ Thread thread = new Thread(() -> {
+ mInstallationSession = mDynSystem.createPartition("userdata", mUserdataSize, false);
+ });
+
+ Log.d(TAG, "Creating partition: userdata");
+ thread.start();
+
+ long installedSize = 0;
+ Progress progress = new Progress("userdata", mUserdataSize, installedSize, 0);
+
+ while (thread.isAlive()) {
+ if (isCancelled()) {
+ return;
+ }
+
+ installedSize = mDynSystem.getInstallationProgress().bytes_processed;
+
+ if (installedSize > progress.mInstalledSize + MIN_PROGRESS_TO_PUBLISH) {
+ progress.mInstalledSize = installedSize;
+ publishProgress(progress);
+ }
+
+ Thread.sleep(10);
+ }
+
+ if (mInstallationSession == null) {
+ throw new IOException(
+ "Failed to start installation with requested size: " + mUserdataSize);
+ }
+ }
+
+ private void installImages() throws IOException, InterruptedException {
+ if (mStream != null) {
+ if (mIsZip) {
+ installStreamingZipUpdate();
+ } else {
+ installStreamingGzUpdate();
+ }
+ } else {
+ installLocalZipUpdate();
+ }
+ }
+
+ private void installStreamingGzUpdate() throws IOException, InterruptedException {
+ Log.d(TAG, "To install a streaming GZ update");
+ installImage("system", mSystemSize, new GZIPInputStream(mStream), 1);
+ }
+
+ private void installStreamingZipUpdate() throws IOException, InterruptedException {
+ Log.d(TAG, "To install a streaming ZIP update");
+
+ ZipInputStream zis = new ZipInputStream(mStream);
+ ZipEntry zipEntry = null;
+
+ int numInstalledPartitions = 1;
+
+ while ((zipEntry = zis.getNextEntry()) != null) {
+ if (installImageFromAnEntry(zipEntry, zis, numInstalledPartitions)) {
+ numInstalledPartitions++;
+ }
+
+ if (isCancelled()) {
+ break;
+ }
+ }
+ }
+
+ private void installLocalZipUpdate() throws IOException, InterruptedException {
+ Log.d(TAG, "To install a local ZIP update");
+
+ Enumeration<? extends ZipEntry> entries = mZipFile.entries();
+ int numInstalledPartitions = 1;
+
+ while (entries.hasMoreElements()) {
+ ZipEntry entry = entries.nextElement();
+ if (installImageFromAnEntry(
+ entry, mZipFile.getInputStream(entry), numInstalledPartitions)) {
+ numInstalledPartitions++;
+ }
+
+ if (isCancelled()) {
+ break;
+ }
+ }
+ }
+
+ private boolean installImageFromAnEntry(ZipEntry entry, InputStream is,
+ int numInstalledPartitions) throws IOException, InterruptedException {
+ 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, numInstalledPartitions);
+
+ return true;
+ }
+
+ private void installImage(String partitionName, long uncompressedSize, InputStream is,
+ int numInstalledPartitions) throws IOException, InterruptedException {
+
+ SparseInputStream sis = new SparseInputStream(new BufferedInputStream(is));
+
+ long unsparseSize = sis.getUnsparseSize();
+
+ final long partitionSize;
+
+ if (unsparseSize != -1) {
+ partitionSize = unsparseSize;
+ Log.d(TAG, partitionName + " is sparse, raw size = " + unsparseSize);
+ } else if (uncompressedSize != -1) {
+ partitionSize = uncompressedSize;
+ Log.d(TAG, partitionName + " is already unsparse, raw size = " + uncompressedSize);
} else {
- throw new InvalidImageUrlException(
- String.format(Locale.US, "Unsupported file source: %s", mUrl));
+ throw new IOException("Cannot get raw size for " + partitionName);
+ }
+
+ Thread thread = new Thread(() -> {
+ mInstallationSession =
+ mDynSystem.createPartition(partitionName, partitionSize, true);
+ });
+
+ Log.d(TAG, "Start creating partition: " + partitionName);
+ thread.start();
+
+ while (thread.isAlive()) {
+ if (isCancelled()) {
+ return;
+ }
+
+ Thread.sleep(10);
+ }
+
+ if (mInstallationSession == null) {
+ throw new IOException(
+ "Failed to start installation with requested size: " + partitionSize);
+ }
+
+ Log.d(TAG, "Start installing: " + partitionName);
+
+ MemoryFile memoryFile = new MemoryFile("dsu_" + partitionName, READ_BUFFER_SIZE);
+ ParcelFileDescriptor pfd = new ParcelFileDescriptor(memoryFile.getFileDescriptor());
+
+ mInstallationSession.setAshmem(pfd, READ_BUFFER_SIZE);
+
+ long installedSize = 0;
+ Progress progress = new Progress(
+ partitionName, partitionSize, installedSize, numInstalledPartitions);
+
+ byte[] bytes = new byte[READ_BUFFER_SIZE];
+ int numBytesRead;
+
+ while ((numBytesRead = sis.read(bytes, 0, READ_BUFFER_SIZE)) != -1) {
+ if (isCancelled()) {
+ return;
+ }
+
+ memoryFile.writeBytes(bytes, 0, 0, numBytesRead);
+
+ if (!mInstallationSession.submitFromAshmem(numBytesRead)) {
+ throw new IOException("Failed write() to DynamicSystem");
+ }
+
+ installedSize += numBytesRead;
+
+ if (installedSize > progress.mInstalledSize + MIN_PROGRESS_TO_PUBLISH) {
+ progress.mInstalledSize = installedSize;
+ publishProgress(progress);
+ }
}
}
@@ -218,20 +412,20 @@ class InstallationAsyncTask extends AsyncTask<String, Long, Throwable> {
mStream.close();
mStream = null;
}
+ if (mZipFile != null) {
+ mZipFile.close();
+ mZipFile = null;
+ }
} catch (IOException e) {
// ignore
}
}
- int getResult() {
- return mResult;
+ boolean isCompleted() {
+ return mIsCompleted;
}
boolean commit() {
- if (mInstallationSession == null) {
- return false;
- }
-
- return mInstallationSession.commit();
+ return mDynSystem.setEnable(true, true);
}
}