Add HidlMemoryUtil
Convenience utilities for working with HidlMemory. Change-Id: I85a46d37de7b89fb48c57f69b1552ca59b802c19 Merged-In: I85a46d37de7b89fb48c57f69b1552ca59b802c19 Bug: 143566068
This commit is contained in:
215
core/java/android/os/HidlMemoryUtil.java
Normal file
215
core/java/android/os/HidlMemoryUtil.java
Normal file
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user