1 /*
2  * Copyright (C) 2018 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 "android_os_NativeHandle.h"
18 
19 #include <nativehelper/JNIHelp.h>
20 #include <nativehelper/ScopedLocalRef.h>
21 
22 #include "core_jni_helpers.h"
23 
24 #define PACKAGE_PATH    "android/os"
25 #define CLASS_NAME      "NativeHandle"
26 #define CLASS_PATH      PACKAGE_PATH "/" CLASS_NAME
27 
28 namespace android {
29 
30 static struct {
31     jclass clazz;
32     jmethodID constructID;  // NativeHandle(int[] fds, int[] ints, boolean owns)
33 
34     jmethodID getFdsID;  // int[] NativeHandle.getFds()
35     jmethodID getIntsID;  // int[] NativeHandle.getInts()
36 } gNativeHandleFields;
37 
MakeJavaNativeHandleObj(JNIEnv * env,const native_handle_t * handle)38 jobject JNativeHandle::MakeJavaNativeHandleObj(
39         JNIEnv *env, const native_handle_t *handle) {
40     if (handle == nullptr) { return nullptr; }
41 
42     const int numFds = handle->numFds;
43     ScopedLocalRef<jintArray> fds(env, env->NewIntArray(numFds));
44     env->SetIntArrayRegion(fds.get(), 0, numFds, &(handle->data[0]));
45 
46     const int numInts = handle->numInts;
47     ScopedLocalRef<jintArray> ints(env, env->NewIntArray(numInts));
48     env->SetIntArrayRegion(ints.get(), 0, numInts, &(handle->data[numFds]));
49 
50     return env->NewObject(gNativeHandleFields.clazz,
51             gNativeHandleFields.constructID, fds.get(), ints.get(), false /*own*/);
52 }
53 
MakeCppNativeHandle(JNIEnv * env,jobject jHandle,EphemeralStorage * storage)54 native_handle_t *JNativeHandle::MakeCppNativeHandle(
55         JNIEnv *env, jobject jHandle, EphemeralStorage *storage) {
56     if (jHandle == nullptr) { return nullptr; }
57 
58     if (!env->IsInstanceOf(jHandle, gNativeHandleFields.clazz)) {
59         jniThrowException(env, "java/lang/ClassCastException",
60                 "jHandle must be an instance of NativeHandle.");
61         return nullptr;
62     }
63 
64     ScopedLocalRef<jintArray> fds(env, (jintArray) env->CallObjectMethod(
65             jHandle, gNativeHandleFields.getFdsID));
66 
67     ScopedLocalRef<jintArray> ints(env, (jintArray) env->CallObjectMethod(
68             jHandle, gNativeHandleFields.getIntsID));
69 
70     const int numFds = (int) env->GetArrayLength(fds.get());
71     const int numInts = (int) env->GetArrayLength(ints.get());
72 
73     native_handle_t *handle = (storage == nullptr)
74             ? native_handle_create(numFds, numInts)
75             : storage->allocTemporaryNativeHandle(numFds, numInts);
76 
77     if (handle != nullptr) {
78         env->GetIntArrayRegion(fds.get(), 0, numFds, &(handle->data[0]));
79         env->GetIntArrayRegion(ints.get(), 0, numInts, &(handle->data[numFds]));
80     } else {
81         jniThrowException(env, "java/lang/OutOfMemoryError",
82                 "Failed to allocate memory for native_handle_t.");
83     }
84 
85     return handle;
86 }
87 
AllocJavaNativeHandleObjArray(JNIEnv * env,jsize length)88 jobjectArray JNativeHandle::AllocJavaNativeHandleObjArray(JNIEnv *env, jsize length) {
89     return env->NewObjectArray(length, gNativeHandleFields.clazz, nullptr);
90 }
91 
register_android_os_NativeHandle(JNIEnv * env)92 int register_android_os_NativeHandle(JNIEnv *env) {
93     jclass clazz = FindClassOrDie(env, CLASS_PATH);
94     gNativeHandleFields.clazz = MakeGlobalRefOrDie(env, clazz);
95 
96     gNativeHandleFields.constructID = GetMethodIDOrDie(env, clazz, "<init>", "([I[IZ)V");
97     gNativeHandleFields.getFdsID = GetMethodIDOrDie(env, clazz, "getFdsAsIntArray", "()[I");
98     gNativeHandleFields.getIntsID = GetMethodIDOrDie(env, clazz, "getInts", "()[I");
99 
100     return 0;
101 }
102 
103 }
104