1 /*
2 * Copyright (C) 2021 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 #define LOG_TAG "IsolatedSplitApp"
18
19 #include <android/log.h>
20 #include <dlfcn.h>
21 #include <stdio.h>
22
23 #include "jni.h"
24
25 #define LOGE(...) __android_log_print(ANDROID_LOG_ERROR, LOG_TAG, __VA_ARGS__)
26 #define LOGI(...) __android_log_print(ANDROID_LOG_INFO, LOG_TAG, __VA_ARGS__)
27
add(JNIEnv * env,jobject thiz,jint numA,jint numB)28 static jint add(JNIEnv* env, jobject thiz, jint numA, jint numB) {
29 return numA + numB;
30 }
31
32 typedef int (*pFuncGetNumber)();
33
get_number_from_other_library(const char * library_file_name,const char * function_name)34 static jint get_number_from_other_library(const char* library_file_name,
35 const char* function_name) {
36 void* handle;
37 char* error;
38 handle = dlopen(library_file_name, RTLD_LAZY);
39 if (!handle) {
40 LOGE("Can't load %s: %s\n", library_file_name, dlerror());
41 return -1;
42 }
43 pFuncGetNumber functionGetNumber = (pFuncGetNumber)dlsym(handle, function_name);
44 if ((error = dlerror()) != NULL) {
45 LOGE("Can't load function %s: %s\n", function_name, error);
46 dlclose(handle);
47 return -2;
48 }
49 int ret = functionGetNumber();
50 dlclose(handle);
51
52 return ret;
53 }
54
get_number_a_via_proxy(JNIEnv * env,jobject thiz)55 static jint get_number_a_via_proxy(JNIEnv* env, jobject thiz) {
56 return get_number_from_other_library("libsplitapp_number_proxy.so", "get_number_a");
57 }
58
get_number_b_via_proxy(JNIEnv * env,jobject thiz)59 static jint get_number_b_via_proxy(JNIEnv* env, jobject thiz) {
60 return get_number_from_other_library("libsplitapp_number_proxy.so", "get_number_b");
61 }
62
get_number_a_from_provider(JNIEnv * env,jobject thiz)63 static jint get_number_a_from_provider(JNIEnv* env, jobject thiz) {
64 return get_number_from_other_library("libsplitapp_number_provider_a.so", "get_number");
65 }
66
get_number_b_from_provider(JNIEnv * env,jobject thiz)67 static jint get_number_b_from_provider(JNIEnv* env, jobject thiz) {
68 return get_number_from_other_library("libsplitapp_number_provider_b.so", "get_number");
69 }
70
71 static const char* classPathName = "com/android/cts/isolatedsplitapp/Native";
72
73 static JNINativeMethod methods[] = {
74 {"add", "(II)I", reinterpret_cast<void*>(add)},
75 {"getNumberAViaProxy", "()I", reinterpret_cast<void**>(get_number_a_via_proxy)},
76 {"getNumberBViaProxy", "()I", reinterpret_cast<void**>(get_number_b_via_proxy)},
77 {"getNumberADirectly", "()I", reinterpret_cast<void**>(get_number_a_from_provider)},
78 {"getNumberBDirectly", "()I", reinterpret_cast<void**>(get_number_b_from_provider)},
79 };
80
registerNativeMethods(JNIEnv * env,const char * className,JNINativeMethod * gMethods,int numMethods)81 static int registerNativeMethods(JNIEnv* env, const char* className, JNINativeMethod* gMethods,
82 int numMethods) {
83 jclass clazz;
84
85 clazz = env->FindClass(className);
86 if (clazz == NULL) {
87 LOGE("Native registration unable to find class '%s'", className);
88 return JNI_FALSE;
89 }
90 if (env->RegisterNatives(clazz, gMethods, numMethods) < 0) {
91 LOGE("RegisterNatives failed for '%s'", className);
92 return JNI_FALSE;
93 }
94
95 return JNI_TRUE;
96 }
97
registerNatives(JNIEnv * env)98 static int registerNatives(JNIEnv* env) {
99 if (!registerNativeMethods(env, classPathName, methods, sizeof(methods) / sizeof(methods[0]))) {
100 return JNI_FALSE;
101 }
102
103 return JNI_TRUE;
104 }
105
JNI_OnLoad(JavaVM * vm,void * reserved)106 jint JNI_OnLoad(JavaVM* vm, void* reserved) {
107 JNIEnv* env = NULL;
108
109 LOGI("JNI_OnLoad %s", classPathName);
110
111 if (vm->GetEnv(reinterpret_cast<void**>(&env), JNI_VERSION_1_6) != JNI_OK) {
112 LOGE("ERROR: GetEnv failed");
113 return JNI_ERR;
114 }
115
116 if (registerNatives(env) != JNI_TRUE) {
117 LOGE("ERROR: registerNatives failed");
118 return JNI_ERR;
119 }
120
121 return JNI_VERSION_1_6;
122 }
123