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