Merge "dynsystem: Fix memory leak" am: a227192105

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

Change-Id: I1bde367ff181ed1c3cca018006fa3e6847a7f464
Signed-off-by: Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
This commit is contained in:
Yi-yo Chiang
2022-04-14 04:33:17 +00:00
committed by Automerger Merge Worker

View File

@@ -16,17 +16,18 @@
package com.android.dynsystem; package com.android.dynsystem;
import android.annotation.NonNull;
import android.content.Context; import android.content.Context;
import android.gsi.AvbPublicKey; import android.gsi.AvbPublicKey;
import android.gsi.IGsiService; 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;
import android.os.MemoryFile; import android.os.SharedMemory;
import android.os.ParcelFileDescriptor;
import android.os.SystemProperties; 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.system.ErrnoException;
import android.util.Log; import android.util.Log;
import android.util.Pair; import android.util.Pair;
import android.util.Range; import android.util.Range;
@@ -39,6 +40,7 @@ import java.io.File;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import java.net.URL; import java.net.URL;
import java.nio.ByteBuffer;
import java.util.Arrays; import java.util.Arrays;
import java.util.Enumeration; import java.util.Enumeration;
import java.util.List; import java.util.List;
@@ -154,6 +156,22 @@ class InstallationAsyncTask extends AsyncTask<String, Long, Throwable> {
void onResult(int resultCode, Throwable detail); 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 int mSharedMemorySize;
private final String mUrl; private final String mUrl;
private final String mDsuSlot; private final String mDsuSlot;
@@ -674,59 +692,66 @@ class InstallationAsyncTask extends AsyncTask<String, Long, Throwable> {
Log.d(TAG, "Start installing: " + partitionName); 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 prevInstalledSize = 0;
long installedSize = 0; try (SharedMemory sharedMemory =
byte[] bytes = new byte[memoryFile.length()]; SharedMemory.create("dsu_buffer_" + partitionName, mSharedMemorySize);
ExecutorService executor = Executors.newSingleThreadExecutor(); MappedMemoryBuffer mappedBuffer =
Future<Boolean> submitPromise = null; new MappedMemoryBuffer(sharedMemory.mapReadWrite())) {
mInstallationSession.setAshmem(sharedMemory.getFdDup(), sharedMemory.getSize());
while (true) { initPartitionProgress(partitionName, partitionSize, /* readonly = */ true);
final int numBytesRead = sis.read(bytes, 0, bytes.length); publishProgress(/* installedSize = */ 0L);
if (submitPromise != null) { long installedSize = 0;
// Wait until the previous submit task is complete. byte[] readBuffer = new byte[sharedMemory.getSize()];
while (true) { ByteBuffer buffer = mappedBuffer.mBuffer;
try { ExecutorService executor = Executors.newSingleThreadExecutor();
if (!submitPromise.get()) { Future<Boolean> submitPromise = null;
throw new IOException("Failed submitFromAshmem() to DynamicSystem");
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. // Ensure the previous submit task (submitPromise) is complete before exiting the
if (installedSize > prevInstalledSize + MIN_PROGRESS_TO_PUBLISH) { // loop.
publishProgress(installedSize); if (numBytesRead < 0) {
prevInstalledSize = installedSize; 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;
} }
} catch (ErrnoException e) {
// Ensure the previous submit task (submitPromise) is complete before exiting the loop. e.rethrowAsIOException();
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;
} }
AvbPublicKey avbPublicKey = new AvbPublicKey(); AvbPublicKey avbPublicKey = new AvbPublicKey();