diff options
| author | 2019-11-12 12:25:38 -0800 | |
|---|---|---|
| committer | 2019-11-21 13:39:12 -0800 | |
| commit | 335114af79736d15f9a4ab9a63b61a7d2f523b1d (patch) | |
| tree | dfc9ed6d7f44a9e0d71197f64dc5650d956af797 | |
| parent | 4659e187334be8181f476e6e8146a72cff9199b3 (diff) | |
Add HidlMemoryUtil
Convenience utilities for working with HidlMemory.
Change-Id: I85a46d37de7b89fb48c57f69b1552ca59b802c19
Bug: 143566068
| -rw-r--r-- | core/java/android/os/HidlMemoryUtil.java | 215 |
1 files changed, 215 insertions, 0 deletions
diff --git a/core/java/android/os/HidlMemoryUtil.java b/core/java/android/os/HidlMemoryUtil.java new file mode 100644 index 000000000000..b08822ddd751 --- /dev/null +++ b/core/java/android/os/HidlMemoryUtil.java @@ -0,0 +1,215 @@ +/* + * Copyright (C) 2019 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package android.os; + +import static android.system.OsConstants.MAP_SHARED; +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.nio.ByteBuffer; +import java.nio.DirectByteBuffer; +import java.util.ArrayList; +import java.util.List; + +/** + * Provides utilities for dealing with HidlMemory. + * + * @hide + */ +public final class HidlMemoryUtil { + static private final String TAG = "HidlMemoryUtil"; + + private HidlMemoryUtil() { + } + + /** + * Copies a byte-array into a new Ashmem region and return it as HidlMemory. + * The returned instance owns the underlying file descriptors, and the client should generally + * call close on it when no longer in use (or otherwise, when the object gets destroyed it will + * be closed). + * + * @param input The input byte array. + * @return A HidlMemory instance, containing a copy of the input. + */ + public static @NonNull + HidlMemory byteArrayToHidlMemory(@NonNull byte[] input) { + return byteArrayToHidlMemory(input, null); + } + + /** + * Copies a byte-array into a new Ashmem region and return it as HidlMemory. + * The returned instance owns the underlying file descriptors, and the client should generally + * call close on it when no longer in use (or otherwise, when the object gets destroyed it will + * be closed). + * + * @param input The input byte array. + * @param name An optional name for the ashmem region. + * @return A HidlMemory instance, containing a copy of the input. + */ + public static @NonNull + HidlMemory byteArrayToHidlMemory(@NonNull byte[] input, @Nullable String name) { + Preconditions.checkNotNull(input); + + if (input.length == 0) { + return new HidlMemory("ashmem", 0, null); + } + + try { + SharedMemory shmem = SharedMemory.create(name != null ? name : "", input.length); + ByteBuffer buffer = shmem.mapReadWrite(); + buffer.put(input); + shmem.unmap(buffer); + NativeHandle handle = new NativeHandle(shmem.getFileDescriptor(), true); + return new HidlMemory("ashmem", input.length, handle); + } catch (ErrnoException e) { + throw new RuntimeException(e); + } + } + + /** + * Copies a byte list into a new Ashmem region and return it as HidlMemory. + * The returned instance owns the underlying file descriptors, and the client should generally + * call close on it when no longer in use (or otherwise, when the object gets destroyed it will + * be closed). + * + * @param input The input byte list. + * @return A HidlMemory instance, containing a copy of the input. + */ + public static @NonNull + HidlMemory byteListToHidlMemory(@NonNull List<Byte> input) { + return byteListToHidlMemory(input, null); + } + + /** + * Copies a byte list into a new Ashmem region and return it as HidlMemory. + * The returned instance owns the underlying file descriptors, and the client should generally + * call close on it when no longer in use (or otherwise, when the object gets destroyed it will + * be closed). + * + * @param input The input byte list. + * @param name An optional name for the ashmem region. + * @return A HidlMemory instance, containing a copy of the input. + */ + public static @NonNull + HidlMemory byteListToHidlMemory(@NonNull List<Byte> input, @Nullable String name) { + Preconditions.checkNotNull(input); + + if (input.isEmpty()) { + return new HidlMemory("ashmem", 0, null); + } + + try { + SharedMemory shmem = SharedMemory.create(name != null ? name : "", input.size()); + ByteBuffer buffer = shmem.mapReadWrite(); + for (Byte b : input) { + buffer.put(b); + } + shmem.unmap(buffer); + NativeHandle handle = new NativeHandle(shmem.getFileDescriptor(), true); + return new HidlMemory("ashmem", input.size(), handle); + } catch (ErrnoException e) { + throw new RuntimeException(e); + } + } + + /** + * Copies all data from a HidlMemory instance into a byte array. + * + * @param mem The HidlMemory instance. Must be of name "ashmem" and of size that doesn't exceed + * {@link Integer#MAX_VALUE}. + * @return A byte array, containing a copy of the input. + */ + public static @NonNull + byte[] hidlMemoryToByteArray(@NonNull HidlMemory mem) { + Preconditions.checkNotNull(mem); + Preconditions.checkArgumentInRange(mem.getSize(), 0L, (long) Integer.MAX_VALUE, + "Memory size"); + Preconditions.checkArgument(mem.getSize() == 0 || mem.getName().equals("ashmem"), + "Unsupported memory type: %s", mem.getName()); + + if (mem.getSize() == 0) { + return new byte[0]; + } + + ByteBuffer buffer = getBuffer(mem); + byte[] result = new byte[buffer.remaining()]; + buffer.get(result); + return result; + } + + /** + * Copies all data from a HidlMemory instance into a byte list. + * + * @param mem The HidlMemory instance. Must be of name "ashmem" and of size that doesn't exceed + * {@link Integer#MAX_VALUE}. + * @return A byte list, containing a copy of the input. + */ + @SuppressLint("ConcreteCollection") + public static @NonNull + ArrayList<Byte> hidlMemoryToByteList(@NonNull HidlMemory mem) { + Preconditions.checkNotNull(mem); + Preconditions.checkArgumentInRange(mem.getSize(), 0L, (long) Integer.MAX_VALUE, + "Memory size"); + Preconditions.checkArgument(mem.getSize() == 0 || mem.getName().equals("ashmem"), + "Unsupported memory type: %s", mem.getName()); + + if (mem.getSize() == 0) { + return new ArrayList<>(); + } + + ByteBuffer buffer = getBuffer(mem); + + ArrayList<Byte> result = new ArrayList<>(buffer.remaining()); + while (buffer.hasRemaining()) { + result.add(buffer.get()); + } + return result; + } + + private static ByteBuffer getBuffer(@NonNull HidlMemory mem) { + try { + final int size = (int) mem.getSize(); + + if (size == 0) { + return ByteBuffer.wrap(new byte[0]); + } + + NativeHandle handle = mem.getHandle(); + + final long address = Os.mmap(0, size, PROT_READ, MAP_SHARED, handle.getFileDescriptor(), + 0); + return new DirectByteBuffer(size, address, handle.getFileDescriptor(), () -> { + try { + Os.munmap(address, size); + } catch (ErrnoException e) { + Log.wtf(TAG, e); + } + }, true); + } catch (ErrnoException e) { + throw new RuntimeException(e); + } + } +} |