xref: /aosp_15_r20/frameworks/base/libs/nativehelper_jvm/JNIPlatformHelp.c (revision d57664e9bc4670b3ecf6748a746a57c557b6bc9e)
1 /*
2  * Copyright (C) 2024 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #include <nativehelper/JNIPlatformHelp.h>
18 
19 #include <stddef.h>
20 
21 #include "JniConstants.h"
22 
GetBufferPosition(JNIEnv * env,jobject nioBuffer)23 static int GetBufferPosition(JNIEnv* env, jobject nioBuffer) {
24     return(*env)->GetIntField(env, nioBuffer, JniConstants_NioBuffer_position(env));
25 }
26 
GetBufferLimit(JNIEnv * env,jobject nioBuffer)27 static int GetBufferLimit(JNIEnv* env, jobject nioBuffer) {
28     return(*env)->GetIntField(env, nioBuffer, JniConstants_NioBuffer_limit(env));
29 }
30 
GetBufferElementSizeShift(JNIEnv * env,jobject nioBuffer)31 static int GetBufferElementSizeShift(JNIEnv* env, jobject nioBuffer) {
32     jclass byteBufferClass = JniConstants_NioByteBufferClass(env);
33     jclass shortBufferClass = JniConstants_NioShortBufferClass(env);
34     jclass charBufferClass = JniConstants_NioCharBufferClass(env);
35     jclass intBufferClass = JniConstants_NioIntBufferClass(env);
36     jclass floatBufferClass = JniConstants_NioFloatBufferClass(env);
37     jclass longBufferClass = JniConstants_NioLongBufferClass(env);
38     jclass doubleBufferClass = JniConstants_NioDoubleBufferClass(env);
39 
40     // Check the type of the Buffer
41     if ((*env)->IsInstanceOf(env, nioBuffer, byteBufferClass)) {
42         return 0;
43     } else if ((*env)->IsInstanceOf(env, nioBuffer, shortBufferClass) ||
44                (*env)->IsInstanceOf(env, nioBuffer, charBufferClass)) {
45         return 1;
46     } else if ((*env)->IsInstanceOf(env, nioBuffer, intBufferClass) ||
47                (*env)->IsInstanceOf(env, nioBuffer, floatBufferClass)) {
48         return 2;
49     } else if ((*env)->IsInstanceOf(env, nioBuffer, longBufferClass) ||
50                (*env)->IsInstanceOf(env, nioBuffer, doubleBufferClass)) {
51         return 3;
52     }
53     return 0;
54 }
55 
jniGetNioBufferBaseArray(JNIEnv * env,jobject nioBuffer)56 jarray jniGetNioBufferBaseArray(JNIEnv* env, jobject nioBuffer) {
57     jmethodID hasArrayMethod = JniConstants_NioBuffer_hasArray(env);
58     jboolean hasArray = (*env)->CallBooleanMethod(env, nioBuffer, hasArrayMethod);
59     if (hasArray) {
60         jmethodID arrayMethod = JniConstants_NioBuffer_array(env);
61         return (*env)->CallObjectMethod(env, nioBuffer, arrayMethod);
62     } else {
63         return NULL;
64     }
65 }
66 
jniGetNioBufferBaseArrayOffset(JNIEnv * env,jobject nioBuffer)67 int jniGetNioBufferBaseArrayOffset(JNIEnv* env, jobject nioBuffer) {
68     jmethodID hasArrayMethod = JniConstants_NioBuffer_hasArray(env);
69     jboolean hasArray = (*env)->CallBooleanMethod(env, nioBuffer, hasArrayMethod);
70     if (hasArray) {
71         jmethodID arrayOffsetMethod = JniConstants_NioBuffer_arrayOffset(env);
72         jint arrayOffset = (*env)->CallIntMethod(env, nioBuffer, arrayOffsetMethod);
73         const int position = GetBufferPosition(env, nioBuffer);
74         jint elementSizeShift = GetBufferElementSizeShift(env, nioBuffer);
75         return (arrayOffset + position) << elementSizeShift;
76     } else {
77         return 0;
78     }
79 }
80 
jniGetNioBufferPointer(JNIEnv * env,jobject nioBuffer)81 jlong jniGetNioBufferPointer(JNIEnv* env, jobject nioBuffer) {
82     // in Java 11, the address field of a HeapByteBuffer contains a non-zero value despite
83     // HeapByteBuffer being a non-direct buffer. In that case, this should still return 0.
84     jmethodID isDirectMethod = JniConstants_NioBuffer_isDirect(env);
85     jboolean isDirect = (*env)->CallBooleanMethod(env, nioBuffer, isDirectMethod);
86     if (isDirect == JNI_FALSE) {
87         return 0L;
88     }
89     jlong baseAddress = (*env)->GetLongField(env, nioBuffer, JniConstants_NioBuffer_address(env));
90     if (baseAddress != 0) {
91         const int position = GetBufferPosition(env, nioBuffer);
92         const int shift = GetBufferElementSizeShift(env, nioBuffer);
93         baseAddress += position << shift;
94     }
95     return baseAddress;
96 }
97 
jniGetNioBufferFields(JNIEnv * env,jobject nioBuffer,jint * position,jint * limit,jint * elementSizeShift)98 jlong jniGetNioBufferFields(JNIEnv* env, jobject nioBuffer,
99                             jint* position, jint* limit, jint* elementSizeShift) {
100     *position = GetBufferPosition(env, nioBuffer);
101     *limit = GetBufferLimit(env, nioBuffer);
102     *elementSizeShift = GetBufferElementSizeShift(env, nioBuffer);
103     return (*env)->GetLongField(env, nioBuffer, JniConstants_NioBuffer_address(env));
104 }
105