diff --git a/app/build.gradle b/app/build.gradle index ac5df08627..f86a4d0c73 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -11,6 +11,7 @@ android { implementation "androidx.viewpager:viewpager:1.0.0" implementation "androidx.drawerlayout:drawerlayout:1.1.0" implementation project(":terminal-view") + implementation project(":native-entrypoint") } defaultConfig { diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 2347586652..910f95726a 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -94,6 +94,16 @@ + + + + + + + + + + diff --git a/native-entrypoint/.gitignore b/native-entrypoint/.gitignore new file mode 100644 index 0000000000..796b96d1c4 --- /dev/null +++ b/native-entrypoint/.gitignore @@ -0,0 +1 @@ +/build diff --git a/native-entrypoint/build.gradle b/native-entrypoint/build.gradle new file mode 100644 index 0000000000..d1405bc5cc --- /dev/null +++ b/native-entrypoint/build.gradle @@ -0,0 +1,51 @@ +plugins { + id "com.jfrog.bintray" version "1.7.3" + id "com.github.dcendents.android-maven" version "2.0" +} + +apply plugin: 'com.android.library' + +ext { + bintrayName = 'native-entrypoint' + publishedGroupId = 'com.termux' + libraryName = 'NativeEntryPoint' + artifact = 'native-entrypoint' + libraryDescription = 'The terminal view used in Termux' + siteUrl = 'https://github.com/termux/termux' + gitUrl = 'https://github.com/termux/termux.git' + libraryVersion = '0.50' +} + +android { + compileSdkVersion project.properties.compileSdkVersion.toInteger() + ndkVersion project.properties.ndkVersion + + dependencies { + implementation "androidx.annotation:annotation:1.1.0" + } + + defaultConfig { + minSdkVersion project.properties.minSdkVersion.toInteger() + targetSdkVersion project.properties.targetSdkVersion.toInteger() + } + + buildTypes { + release { + minifyEnabled false + proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' + } + } + + externalNativeBuild { + ndkBuild { + path "src/main/jni/Android.mk" + } + } + + compileOptions { + sourceCompatibility JavaVersion.VERSION_1_8 + targetCompatibility JavaVersion.VERSION_1_8 + } +} + +apply from: '../scripts/bintray-publish.gradle' diff --git a/native-entrypoint/proguard-rules.pro b/native-entrypoint/proguard-rules.pro new file mode 100644 index 0000000000..f1b424510d --- /dev/null +++ b/native-entrypoint/proguard-rules.pro @@ -0,0 +1,21 @@ +# Add project specific ProGuard rules here. +# You can control the set of applied configuration files using the +# proguardFiles setting in build.gradle. +# +# For more details, see +# http://developer.android.com/guide/developing/tools/proguard.html + +# If your project uses WebView with JS, uncomment the following +# and specify the fully qualified class name to the JavaScript interface +# class: +#-keepclassmembers class fqcn.of.javascript.interface.for.webview { +# public *; +#} + +# Uncomment this to preserve the line number information for +# debugging stack traces. +#-keepattributes SourceFile,LineNumberTable + +# If you keep the line number information, uncomment this to +# hide the original source file name. +#-renamesourcefileattribute SourceFile diff --git a/native-entrypoint/src/main/AndroidManifest.xml b/native-entrypoint/src/main/AndroidManifest.xml new file mode 100644 index 0000000000..281f254520 --- /dev/null +++ b/native-entrypoint/src/main/AndroidManifest.xml @@ -0,0 +1,4 @@ + + + diff --git a/native-entrypoint/src/main/jni/Android.mk b/native-entrypoint/src/main/jni/Android.mk new file mode 100644 index 0000000000..01a0ea3aa1 --- /dev/null +++ b/native-entrypoint/src/main/jni/Android.mk @@ -0,0 +1,6 @@ +LOCAL_PATH:= $(call my-dir) +include $(CLEAR_VARS) +LOCAL_MODULE:= libnative-entrypoint +LOCAL_SRC_FILES:= main.cpp +LOCAL_LDLIBS:= -llog -landroid -ldl +include $(BUILD_SHARED_LIBRARY) diff --git a/native-entrypoint/src/main/jni/main.cpp b/native-entrypoint/src/main/jni/main.cpp new file mode 100644 index 0000000000..213c4a5826 --- /dev/null +++ b/native-entrypoint/src/main/jni/main.cpp @@ -0,0 +1,85 @@ +#include +/* + * Copyright (C) 2010 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. + * + */ + +//BEGIN_INCLUDE(all) +#include +#include + +#include +#include + +#define LOGI(...) ((void)__android_log_print(ANDROID_LOG_INFO, "native-activity", __VA_ARGS__)) +#define LOGW(...) ((void)__android_log_print(ANDROID_LOG_WARN, "native-activity", __VA_ARGS__)) + +jstring ANativeActivity_getIntent(ANativeActivity* activity, const char* intentName) { + JNIEnv* env = activity->env; + jobject me = activity->clazz; + + jclass acl = env->GetObjectClass(me); //class pointer of NativeActivity + jmethodID giid = env->GetMethodID(acl, "getIntent", "()Landroid/content/Intent;"); + jobject intent = env->CallObjectMethod(me, giid); //Got our intent + + jclass icl = env->GetObjectClass(intent); //class pointer of Intent + jmethodID gseid = env->GetMethodID(icl, "getStringExtra", "(Ljava/lang/String;)Ljava/lang/String;"); + + return (jstring)env->CallObjectMethod(intent, gseid, env->NewStringUTF(intentName)); +} + +void ANativeActivity_onCreate(ANativeActivity* activity, void* savedState, size_t savedStateSize) { + JNIEnv* env = activity->env; + jstring dylib_path = ANativeActivity_getIntent(activity, "DYLIB_PATH"); + + const char *path = env->GetStringUTFChars(dylib_path, 0); + void* handle = dlopen(path, RTLD_LAZY | RTLD_GLOBAL); + + env->ReleaseStringUTFChars(dylib_path, path); + + { + if (handle == NULL) { + char* errorText = dlerror(); + LOGW("ERROR!!! %s\n", errorText); + printf("%s\n", errorText); + ANativeActivity_finish(activity); + return; + } + + void* entryPoint = dlsym(handle, "ANativeActivity_onCreate"); + + if (entryPoint) { + LOGI("%s found.\n", "ANativeActivity_onCreate"); + } else { + entryPoint = dlsym(handle, __func__); + + if (entryPoint) { + LOGI("%s found.\n", __func__); + } + } + + if (entryPoint) { + LOGI("calling main...\n"); + (*(void(*)(ANativeActivity*, void*, size_t))entryPoint)(activity, savedState, savedStateSize); + LOGI("exited!...\n"); + } else { + char* errorText = dlerror(); + LOGW("ERROR!!! %s\n", errorText); + printf("%s\n", errorText); + } + + dlclose(handle); + } +} diff --git a/settings.gradle b/settings.gradle index 2cfc62326b..bdbf0720cc 100644 --- a/settings.gradle +++ b/settings.gradle @@ -1 +1 @@ -include ':app', ':terminal-emulator', ':terminal-view' +include ':app', ':terminal-emulator', ':terminal-view', ':native-entrypoint'