From d5065ba8a54800fc14aa5ddc1a0f15b5b8f808e7 Mon Sep 17 00:00:00 2001 From: Ytai Ben-Tsvi Date: Thu, 27 Feb 2020 15:36:05 -0800 Subject: [PATCH] Pass models to soundtrigger middleware with shared memory This both avoids the need to make extra copied for the models and allows exceeding the parcel size limits. Bug: 150100907 Test: Manual testing of basic sound trigger functionality Change-Id: Ic4c5c1a9de3e29b1b6fa82442254e1afe7daec19 --- .../hardware/soundtrigger/ConversionUtil.java | 23 ++++++++++- core/java/android/os/HidlMemoryUtil.java | 41 ++++++++++++++++--- .../soundtrigger_middleware/SoundModel.aidl | 4 +- .../ConversionUtil.java | 4 +- .../SoundTriggerMiddlewareImplTest.java | 20 ++++++++- 5 files changed, 81 insertions(+), 11 deletions(-) diff --git a/core/java/android/hardware/soundtrigger/ConversionUtil.java b/core/java/android/hardware/soundtrigger/ConversionUtil.java index dbf33cade60c9..3d763e630bd0e 100644 --- a/core/java/android/hardware/soundtrigger/ConversionUtil.java +++ b/core/java/android/hardware/soundtrigger/ConversionUtil.java @@ -32,7 +32,11 @@ import android.media.soundtrigger_middleware.RecognitionMode; import android.media.soundtrigger_middleware.SoundModel; import android.media.soundtrigger_middleware.SoundTriggerModuleDescriptor; import android.media.soundtrigger_middleware.SoundTriggerModuleProperties; +import android.os.SharedMemory; +import android.system.ErrnoException; +import java.io.FileDescriptor; +import java.nio.ByteBuffer; import java.util.Arrays; import java.util.UUID; @@ -105,7 +109,8 @@ class ConversionUtil { aidlModel.type = apiModel.type; aidlModel.uuid = api2aidlUuid(apiModel.uuid); aidlModel.vendorUuid = api2aidlUuid(apiModel.vendorUuid); - aidlModel.data = Arrays.copyOf(apiModel.data, apiModel.data.length); + aidlModel.data = byteArrayToSharedMemory(apiModel.data, "SoundTrigger SoundModel"); + aidlModel.dataSize = apiModel.data.length; return aidlModel; } @@ -352,4 +357,20 @@ class ConversionUtil { } return result; } + + private static @Nullable FileDescriptor byteArrayToSharedMemory(byte[] data, String name) { + if (data.length == 0) { + return null; + } + + try { + SharedMemory shmem = SharedMemory.create(name != null ? name : "", data.length); + ByteBuffer buffer = shmem.mapReadWrite(); + buffer.put(data); + shmem.unmap(buffer); + return shmem.getFileDescriptor(); + } catch (ErrnoException e) { + throw new RuntimeException(e); + } + } } diff --git a/core/java/android/os/HidlMemoryUtil.java b/core/java/android/os/HidlMemoryUtil.java index b08822ddd751f..4252fe30f4ad5 100644 --- a/core/java/android/os/HidlMemoryUtil.java +++ b/core/java/android/os/HidlMemoryUtil.java @@ -21,14 +21,13 @@ import static android.system.OsConstants.PROT_READ; import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.SuppressLint; -import android.annotation.SystemApi; -import android.annotation.TestApi; import android.system.ErrnoException; import android.system.Os; import android.util.Log; import com.android.internal.util.Preconditions; +import java.io.FileDescriptor; import java.nio.ByteBuffer; import java.nio.DirectByteBuffer; import java.util.ArrayList; @@ -82,8 +81,7 @@ public final class HidlMemoryUtil { ByteBuffer buffer = shmem.mapReadWrite(); buffer.put(input); shmem.unmap(buffer); - NativeHandle handle = new NativeHandle(shmem.getFileDescriptor(), true); - return new HidlMemory("ashmem", input.length, handle); + return sharedMemoryToHidlMemory(shmem); } catch (ErrnoException e) { throw new RuntimeException(e); } @@ -128,8 +126,7 @@ public final class HidlMemoryUtil { buffer.put(b); } shmem.unmap(buffer); - NativeHandle handle = new NativeHandle(shmem.getFileDescriptor(), true); - return new HidlMemory("ashmem", input.size(), handle); + return sharedMemoryToHidlMemory(shmem); } catch (ErrnoException e) { throw new RuntimeException(e); } @@ -189,6 +186,38 @@ public final class HidlMemoryUtil { return result; } + /** + * Converts a SharedMemory to a HidlMemory without copying. + * + * @param shmem The shared memory object. Null means "empty" and will still result in a non-null + * return value. + * @return The HidlMemory instance. + */ + @NonNull public static HidlMemory sharedMemoryToHidlMemory(@Nullable SharedMemory shmem) { + if (shmem == null) { + return new HidlMemory("ashmem", 0, null); + } + return fileDescriptorToHidlMemory(shmem.getFileDescriptor(), shmem.getSize()); + } + + /** + * Converts a FileDescriptor to a HidlMemory without copying. + * + * @param fd The FileDescriptor object. Null is allowed if size is 0 and will still result in + * a non-null return value. + * @param size The size of the memory buffer. + * @return The HidlMemory instance. + */ + @NonNull public static HidlMemory fileDescriptorToHidlMemory(@Nullable FileDescriptor fd, + int size) { + Preconditions.checkArgument(fd != null || size == 0); + if (fd == null) { + return new HidlMemory("ashmem", 0, null); + } + NativeHandle handle = new NativeHandle(fd, true); + return new HidlMemory("ashmem", size, handle); + } + private static ByteBuffer getBuffer(@NonNull HidlMemory mem) { try { final int size = (int) mem.getSize(); diff --git a/media/java/android/media/soundtrigger_middleware/SoundModel.aidl b/media/java/android/media/soundtrigger_middleware/SoundModel.aidl index fba1ee5078361..81d8291e85aa3 100644 --- a/media/java/android/media/soundtrigger_middleware/SoundModel.aidl +++ b/media/java/android/media/soundtrigger_middleware/SoundModel.aidl @@ -32,5 +32,7 @@ parcelable SoundModel { * was build for */ String vendorUuid; /** Opaque data transparent to Android framework */ - byte[] data; + FileDescriptor data; + /** Size of the above data, in bytes. */ + int dataSize; } diff --git a/services/core/java/com/android/server/soundtrigger_middleware/ConversionUtil.java b/services/core/java/com/android/server/soundtrigger_middleware/ConversionUtil.java index a641f06ac3caf..1d31285ed9c7b 100644 --- a/services/core/java/com/android/server/soundtrigger_middleware/ConversionUtil.java +++ b/services/core/java/com/android/server/soundtrigger_middleware/ConversionUtil.java @@ -196,8 +196,8 @@ class ConversionUtil { hidlModel.header.type = aidl2hidlSoundModelType(aidlModel.type); hidlModel.header.uuid = aidl2hidlUuid(aidlModel.uuid); hidlModel.header.vendorUuid = aidl2hidlUuid(aidlModel.vendorUuid); - hidlModel.data = HidlMemoryUtil.byteArrayToHidlMemory(aidlModel.data, - "SoundTrigger SoundModel"); + hidlModel.data = HidlMemoryUtil.fileDescriptorToHidlMemory(aidlModel.data, + aidlModel.dataSize); return hidlModel; } diff --git a/services/tests/servicestests/src/com/android/server/soundtrigger_middleware/SoundTriggerMiddlewareImplTest.java b/services/tests/servicestests/src/com/android/server/soundtrigger_middleware/SoundTriggerMiddlewareImplTest.java index c56034adb73db..06b5fe48c4cfa 100644 --- a/services/tests/servicestests/src/com/android/server/soundtrigger_middleware/SoundTriggerMiddlewareImplTest.java +++ b/services/tests/servicestests/src/com/android/server/soundtrigger_middleware/SoundTriggerMiddlewareImplTest.java @@ -60,6 +60,8 @@ import android.os.HwParcel; import android.os.IHwBinder; import android.os.IHwInterface; import android.os.RemoteException; +import android.os.SharedMemory; +import android.system.ErrnoException; import android.util.Pair; import org.junit.Before; @@ -71,6 +73,9 @@ import org.mockito.Mock; import org.mockito.Mockito; import org.mockito.stubbing.Answer; +import java.io.FileDescriptor; +import java.nio.ByteBuffer; + @RunWith(Parameterized.class) public class SoundTriggerMiddlewareImplTest { private static final String TAG = "SoundTriggerMiddlewareImplTest"; @@ -104,12 +109,25 @@ public class SoundTriggerMiddlewareImplTest { return createSoundModel(SoundModelType.GENERIC); } + private static FileDescriptor byteArrayToFileDescriptor(byte[] data) { + try { + SharedMemory shmem = SharedMemory.create("", data.length); + ByteBuffer buffer = shmem.mapReadWrite(); + buffer.put(data); + return shmem.getFileDescriptor(); + } catch (ErrnoException e) { + throw new RuntimeException(e); + } + } + private static SoundModel createSoundModel(int type) { SoundModel model = new SoundModel(); model.type = type; model.uuid = "12345678-2345-3456-4567-abcdef987654"; model.vendorUuid = "87654321-5432-6543-7654-456789fedcba"; - model.data = new byte[]{91, 92, 93, 94, 95}; + byte[] data = new byte[]{91, 92, 93, 94, 95}; + model.data = byteArrayToFileDescriptor(data); + model.dataSize = data.length; return model; }