Merge "dynsystem: Fix memory leak"
diff --git a/packages/DynamicSystemInstallationService/src/com/android/dynsystem/InstallationAsyncTask.java b/packages/DynamicSystemInstallationService/src/com/android/dynsystem/InstallationAsyncTask.java
index 62e53d6..a41399f 100644
--- a/packages/DynamicSystemInstallationService/src/com/android/dynsystem/InstallationAsyncTask.java
+++ b/packages/DynamicSystemInstallationService/src/com/android/dynsystem/InstallationAsyncTask.java
@@ -16,17 +16,18 @@
package com.android.dynsystem;
+import android.annotation.NonNull;
import android.content.Context;
import android.gsi.AvbPublicKey;
import android.gsi.IGsiService;
import android.net.Uri;
import android.os.AsyncTask;
import android.os.Build;
-import android.os.MemoryFile;
-import android.os.ParcelFileDescriptor;
+import android.os.SharedMemory;
import android.os.SystemProperties;
import android.os.image.DynamicSystemManager;
import android.service.persistentdata.PersistentDataBlockManager;
+import android.system.ErrnoException;
import android.util.Log;
import android.util.Pair;
import android.util.Range;
@@ -39,6 +40,7 @@
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
+import java.nio.ByteBuffer;
import java.util.Arrays;
import java.util.Enumeration;
import java.util.List;
@@ -154,6 +156,22 @@
void onResult(int resultCode, Throwable detail);
}
+ private static class MappedMemoryBuffer implements AutoCloseable {
+ public ByteBuffer mBuffer;
+
+ MappedMemoryBuffer(@NonNull ByteBuffer buffer) {
+ mBuffer = buffer;
+ }
+
+ @Override
+ public void close() {
+ if (mBuffer != null) {
+ SharedMemory.unmap(mBuffer);
+ mBuffer = null;
+ }
+ }
+ }
+
private final int mSharedMemorySize;
private final String mUrl;
private final String mDsuSlot;
@@ -674,59 +692,66 @@
Log.d(TAG, "Start installing: " + partitionName);
- MemoryFile memoryFile = new MemoryFile("dsu_" + partitionName, mSharedMemorySize);
- ParcelFileDescriptor pfd = new ParcelFileDescriptor(memoryFile.getFileDescriptor());
-
- mInstallationSession.setAshmem(pfd, memoryFile.length());
-
- initPartitionProgress(partitionName, partitionSize, /* readonly = */ true);
- publishProgress(/* installedSize = */ 0L);
-
long prevInstalledSize = 0;
- long installedSize = 0;
- byte[] bytes = new byte[memoryFile.length()];
- ExecutorService executor = Executors.newSingleThreadExecutor();
- Future<Boolean> submitPromise = null;
+ try (SharedMemory sharedMemory =
+ SharedMemory.create("dsu_buffer_" + partitionName, mSharedMemorySize);
+ MappedMemoryBuffer mappedBuffer =
+ new MappedMemoryBuffer(sharedMemory.mapReadWrite())) {
+ mInstallationSession.setAshmem(sharedMemory.getFdDup(), sharedMemory.getSize());
- while (true) {
- final int numBytesRead = sis.read(bytes, 0, bytes.length);
+ initPartitionProgress(partitionName, partitionSize, /* readonly = */ true);
+ publishProgress(/* installedSize = */ 0L);
- if (submitPromise != null) {
- // Wait until the previous submit task is complete.
- while (true) {
- try {
- if (!submitPromise.get()) {
- throw new IOException("Failed submitFromAshmem() to DynamicSystem");
+ long installedSize = 0;
+ byte[] readBuffer = new byte[sharedMemory.getSize()];
+ ByteBuffer buffer = mappedBuffer.mBuffer;
+ ExecutorService executor = Executors.newSingleThreadExecutor();
+ Future<Boolean> submitPromise = null;
+
+ while (true) {
+ final int numBytesRead = sis.read(readBuffer, 0, readBuffer.length);
+
+ if (submitPromise != null) {
+ // Wait until the previous submit task is complete.
+ while (true) {
+ try {
+ if (!submitPromise.get()) {
+ throw new IOException("Failed submitFromAshmem() to DynamicSystem");
+ }
+ break;
+ } catch (InterruptedException e) {
+ // Ignore.
}
- break;
- } catch (InterruptedException e) {
- // Ignore.
+ }
+
+ // Publish the progress of the previous submit task.
+ if (installedSize > prevInstalledSize + MIN_PROGRESS_TO_PUBLISH) {
+ publishProgress(installedSize);
+ prevInstalledSize = installedSize;
}
}
- // Publish the progress of the previous submit task.
- if (installedSize > prevInstalledSize + MIN_PROGRESS_TO_PUBLISH) {
- publishProgress(installedSize);
- prevInstalledSize = installedSize;
+ // Ensure the previous submit task (submitPromise) is complete before exiting the
+ // loop.
+ if (numBytesRead < 0) {
+ break;
}
+
+ if (isCancelled()) {
+ return;
+ }
+
+ buffer.position(0);
+ buffer.put(readBuffer, 0, numBytesRead);
+ submitPromise =
+ executor.submit(() -> mInstallationSession.submitFromAshmem(numBytesRead));
+
+ // Even though we update the bytes counter here, the actual progress is updated only
+ // after the submit task (submitPromise) is complete.
+ installedSize += numBytesRead;
}
-
- // Ensure the previous submit task (submitPromise) is complete before exiting the loop.
- if (numBytesRead < 0) {
- break;
- }
-
- if (isCancelled()) {
- return;
- }
-
- memoryFile.writeBytes(bytes, 0, 0, numBytesRead);
- submitPromise =
- executor.submit(() -> mInstallationSession.submitFromAshmem(numBytesRead));
-
- // Even though we update the bytes counter here, the actual progress is updated only
- // after the submit task (submitPromise) is complete.
- installedSize += numBytesRead;
+ } catch (ErrnoException e) {
+ e.rethrowAsIOException();
}
AvbPublicKey avbPublicKey = new AvbPublicKey();