blob: e03a3d3010b9d64c5f0a3adcc08a065368b58afd [file] [log] [blame]
/*
* Copyright (C) 2020 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.libnativehelper.mts;
import android.test.AndroidTestCase;
import java.io.FileDescriptor;
import java.io.IOException;
import java.lang.ref.Reference;
import java.lang.ref.SoftReference;
import java.nio.Buffer;
import java.nio.ByteBuffer;
import java.nio.ShortBuffer;
import java.nio.IntBuffer;
import java.nio.FloatBuffer;
import java.nio.DoubleBuffer;
import org.junit.Assert;
public class JniHelpTest extends AndroidTestCase {
private static native void throwException(String className, String message);
private static native void throwExceptionWithIntFormat(String className,
String format,
int value);
private static native void throwNullPointerException(String message);
private static native void throwRuntimeException(String message);
private static native void throwIOException(int cause) throws IOException;
private static native void logException(Throwable throwable);
private static native FileDescriptor fileDescriptorCreate(int unixFd);
private static native int fileDescriptorGetFD(FileDescriptor jiofd);
private static native int fileDescriptorGetFDCompatQR(FileDescriptor jiofd);
private static native void fileDescriptorSetFD(FileDescriptor jiofd, int unixFd);
private static native ByteBuffer allocateDirectNonHeapBuffer(int length);
private static native void assertBufferBaseArrayOffsetBytes(Buffer b, int offset);
private static native void assertBufferPosition(Buffer b, int position);
private static native void assertBufferLimit(Buffer b, int limit);
private static native void assertBufferElementSizeShift(Buffer b, int elementSizeShift);
private static native long getBufferBaseAddress(Buffer b);
private static native long getDirectBufferAddress(Buffer b);
private static native void assertBufferPointer(Buffer b, long address);
private static native String createString(String input);
static {
System.loadLibrary("nativehelper_mts_jni");
}
public void testThrowException() {
final String message = "Because test";
try {
throwException("java/lang/RuntimeException", message);
fail("Unreachable");
} catch (RuntimeException e) {
assertEquals(message, e.getMessage());
}
}
public void testThrowExceptionWithIntFormat() {
final String format = "Because test %d";
try {
throwExceptionWithIntFormat("java/lang/RuntimeException", format, 101);
fail("Unreachable");
} catch (RuntimeException e) {
assertEquals("Because test 101", e.getMessage());
}
}
public void testThrowNullPointerException() {
final String message = "Because another test";
try {
throwNullPointerException(message);
fail("Unreachable");
} catch (NullPointerException e) {
assertEquals(message, e.getMessage());
}
}
public void testThrowRuntimeException() {
final String message = "Because test again";
try {
throwRuntimeException(message);
fail("Unreachable");
} catch (RuntimeException e) {
assertEquals(message, e.getMessage());
}
}
public void testIOException() {
String s1 = null;
try {
throwIOException(70);
fail("Unreachable");
} catch (IOException e) {
s1 = e.getMessage();
}
assertNotNull(s1);
String s2 = null;
try {
throwIOException(71);
fail("Unreachable");
} catch (IOException e) {
s2 = e.getMessage();
}
assertNotNull(s2);
assertFalse(s1.equals(s2));
}
public void testLogException() {
try {
throw new RuntimeException("Exception for logging test");
} catch (RuntimeException e) {
// TODO: Mock/redirect logcat to test output is logged appropriately.
// Or add extend JNIHelp API to write to a buffer or file.
logException(e);
}
}
public void testFileDescriptorCreate() {
int [] unix_fds = { -999, -1, 0, 1, 1000 };
for (int unix_fd : unix_fds) {
FileDescriptor f0 = fileDescriptorCreate(unix_fd);
assertNotNull(f0);
assertSame(f0.getClass(), FileDescriptor.class);
}
}
public void testFileDescriptorGetNull() {
assertEquals(-1, fileDescriptorGetFD(null));
}
public void testFileDescriptorGetNonNull() {
final int UNIX_FD = 77;
FileDescriptor jiofd = fileDescriptorCreate(UNIX_FD);
assertEquals(UNIX_FD, fileDescriptorGetFD(jiofd));
}
public void testFileDescriptorSetNull() {
try {
fileDescriptorSetFD(null, 1);
fail("Expected NullPointerException to be thrown.");
} catch (NullPointerException e) {}
}
public void testFileDescriptorSetNonNull() {
final int UNIX_FD = 127;
FileDescriptor jiofd = fileDescriptorCreate(0);
fileDescriptorSetFD(jiofd, UNIX_FD);
assertEquals(UNIX_FD, fileDescriptorGetFD(jiofd));
}
public void testFileDescriptorSetCompatQRNonNull() {
final int UNIX_FD = 127;
FileDescriptor jiofd = fileDescriptorCreate(0);
fileDescriptorSetFD(jiofd, UNIX_FD);
assertEquals(UNIX_FD, fileDescriptorGetFDCompatQR(jiofd));
}
private static void checkNioBufferApi(final Buffer b,
int baseArrayOffsetBytes,
int position,
int limit,
int elementSizeShift) {
assertTrue(baseArrayOffsetBytes == 0 || b.hasArray());
assertBufferBaseArrayOffsetBytes(b, baseArrayOffsetBytes);
assertBufferPosition(b, position);
assertBufferLimit(b, limit);
assertBufferElementSizeShift(b, elementSizeShift);
long baseAddress = getBufferBaseAddress(b);
assertEquals(baseAddress, getDirectBufferAddress(b));
if (b.isDirect() || baseAddress != 0L) {
Assert.assertNotEquals(0L, baseAddress);
long currentAddress = baseAddress + (position << elementSizeShift);
assertBufferPointer(b, currentAddress);
}
}
private static void checkNioHeapBuffers(final ByteBuffer bb) {
byte [] data = new byte[8];
for (int i = 0; i < 4; ++i, bb.get(data)) {
final int arrayOffset = bb.hasArray() ? bb.arrayOffset() : 0;
final int position = bb.position();
final int limit = bb.limit();
int shift = 0;
int baseArrayOffsetBytes = bb.hasArray() ? (arrayOffset + position) << shift : 0;
assertEquals(i * data.length, position);
checkNioBufferApi(bb, baseArrayOffsetBytes, position, limit, shift);
checkNioBufferApi(bb.asReadOnlyBuffer(), 0, position, limit, shift);
shift += 1;
checkNioBufferApi(bb.asCharBuffer(), 0, 0, (limit - position) >> shift, shift);
checkNioBufferApi(bb.asShortBuffer(), 0, 0, (limit - position) >> shift, shift);
shift += 1;
checkNioBufferApi(bb.asIntBuffer(), 0, 0, (limit - position) >> shift, shift);
checkNioBufferApi(bb.asFloatBuffer(), 0, 0, (limit - position) >> shift, shift);
shift += 1;
checkNioBufferApi(bb.asLongBuffer(), 0, 0, (limit - position) >> shift, shift);
checkNioBufferApi(bb.asDoubleBuffer(), 0, 0, (limit - position) >> shift, shift);
}
}
public void testNioHeapByteBuffer() {
ByteBuffer bb = ByteBuffer.allocate(128);
assertFalse(bb.isDirect());
assertTrue(bb.hasArray());
checkNioHeapBuffers(bb);
}
public void testNioDirectHeapByteBuffer() {
// Android implementation detail: allocateDirect() allocates a managed array in a
// non-movable managed heap.
ByteBuffer bb = ByteBuffer.allocateDirect(128);
assertTrue(bb.isDirect());
assertTrue(bb.hasArray());
checkNioHeapBuffers(bb);
}
public void testNioDirectNonHeapByteBuffer() {
ByteBuffer bb = allocateDirectNonHeapBuffer(128); // allocates native NewDirectByteBuffer()
assertTrue(bb.isDirect());
assertFalse(bb.hasArray());
checkNioHeapBuffers(bb);
}
private void checkNioXHeapBuffer(final Buffer b, final int shift, final int step) {
b.position(0);
while (b.position() < b.limit()) {
final int baseArrayOffsetBytes = (b.arrayOffset() + b.position()) << shift;
checkNioBufferApi(b, baseArrayOffsetBytes, b.position(), b.limit(), shift);
final int newPosition = Math.min(b.limit(), b.position() + step);
b.position(newPosition);
}
}
public void checkNioXHeapBuffers(final Buffer b, final int shift) {
for (int step = 1; step < b.limit() / 2 - 1; ++step) {
checkNioXHeapBuffer(b, shift, step);
}
}
public void testNioHeapShortBuffer() {
checkNioXHeapBuffers(ShortBuffer.allocate(64), 1);
}
public void testNioHeapIntBuffer() {
checkNioXHeapBuffers(IntBuffer.allocate(64), 2);
}
public void testNioHeapFloatBuffer() {
checkNioXHeapBuffers(FloatBuffer.allocate(64), 2);
}
public void testNioHeapDoubleBuffer() {
checkNioXHeapBuffers(DoubleBuffer.allocate(64), 3);
}
public void testNioWrappedHeapByteBuffer() {
final byte [] backing = new byte[16];
final ByteBuffer bb = ByteBuffer.wrap(backing, 4, 12);
checkNioXHeapBuffers(bb, 0);
}
public void testCreateString() {
String input = "The treacherous mountain path lay ahead.";
String output = createString(input);
assertEquals(input, output);
assertNotSame(input, output);
}
}