diff --git a/build.gradle b/build.gradle index 745a141aa04..fdc79f87a39 100644 --- a/build.gradle +++ b/build.gradle @@ -138,14 +138,14 @@ void setupCompilationFlags() { "android_arm32": ["-target", getTargetArg("android_arm32"), "--sysroot=$android_arm32SysrootDir", - "-D__ANDROID__", "-DUSE_GCC_UNWIND=1", "-DUSE_ELF_SYMBOLS=1", "-DELFSIZE=32", + "-D__ANDROID__", "-DUSE_GCC_UNWIND=1", "-DUSE_ELF_SYMBOLS=1", "-DELFSIZE=32", "-DANDROID", // HACKS! "-I$android_arm32SysrootDir/usr/include/c++/4.9.x", "-I$android_arm32SysrootDir/usr/include/c++/4.9.x/arm-linux-androideabi"], "android_arm64": ["-target", getTargetArg("android_arm64"), "--sysroot=$android_arm64SysrootDir", - "-D__ANDROID__", "-DUSE_GCC_UNWIND=1", "-DUSE_ELF_SYMBOLS=1", "-DELFSIZE=64", + "-D__ANDROID__", "-DUSE_GCC_UNWIND=1", "-DUSE_ELF_SYMBOLS=1", "-DELFSIZE=64", "-DANDROID", // HACKS! "-I$android_arm64SysrootDir/usr/include/c++/4.9.x", "-I$android_arm64SysrootDir/usr/include/c++/4.9.x/aarch64-linux-android"] diff --git a/runtime/src/launcher/cpp/androidLauncher.cpp b/runtime/src/launcher/cpp/androidLauncher.cpp new file mode 100644 index 00000000000..d0f32deb001 --- /dev/null +++ b/runtime/src/launcher/cpp/androidLauncher.cpp @@ -0,0 +1,214 @@ +/* + * Copyright 2010-2017 JetBrains s.r.o. + * + * 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. + */ + +#include "Memory.h" +#include "Natives.h" +#include "Runtime.h" +#include "KString.h" +#include "Types.h" + +#ifdef ANDROID +#include +#include +#include +#include + +#include "androidLauncher.h" + +#include + +#define LOGI(...) ((void)__android_log_print(ANDROID_LOG_INFO, "Konan_main", __VA_ARGS__)) +#define LOGE(...) ((void)__android_log_print(ANDROID_LOG_ERROR, "Konan_main", __VA_ARGS__)) + +/* For debug builds, always enable the debug traces in this library */ +#ifndef NDEBUG +# define LOGV(...) ((void)__android_log_print(ANDROID_LOG_VERBOSE, "Konan_main", __VA_ARGS__)) +#else +# define LOGV(...) ((void)0) +#endif + +//--- main --------------------------------------------------------------------// +extern "C" KInt Konan_start(const ObjHeader*); + +static int pipeC, pipeKonan; + +static NativeActivityState nativeActivityState; + +extern "C" void getNativeActivityState(NativeActivityState* state) { + state->activity = nativeActivityState.activity; + state->savedState = nativeActivityState.savedState; + state->savedStateSize = nativeActivityState.savedStateSize; + state->looper = nativeActivityState.looper; +} + +extern "C" void notifySysEventProcessed(int fd) { + if (fd != pipeKonan) return; + int8_t message; + write(pipeKonan, &message, sizeof(message)); +} + +static void* entry(void* param) { + ALooper* looper = ALooper_prepare(ALOOPER_PREPARE_ALLOW_NON_CALLBACKS); + ALooper_addFd(looper, pipeKonan, LOOPER_ID_SYS, ALOOPER_EVENT_INPUT, NULL, NULL); + nativeActivityState.looper = looper; + + RuntimeState* state = InitRuntime(); + + if (state == nullptr) { + LOGE("Unable to init runtime\n"); + return nullptr; + } + + KInt exitStatus; + { + ObjHolder args; + AllocArrayInstance(theArrayTypeInfo, 0, args.slot()); + exitStatus = Konan_start(args.obj()); + } + + DeinitRuntime(state); + return nullptr; +} + +static void runKonan_start() { + int pipes[2]; + if (socketpair(AF_UNIX, SOCK_STREAM, 0, pipes)) { + LOGE("Could not create pipe: %s", strerror(errno)); + return; + } + pipeC = pipes[0]; + pipeKonan = pipes[1]; + + pthread_attr_t attr; + pthread_attr_init(&attr); + pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED); + pthread_t thread; + pthread_create(&thread, &attr, entry, nullptr); +} + +static void putEventSynchronously(void* event) { + uint64_t value = static_cast(reinterpret_cast(event)); + if (write(pipeC, &value, sizeof(value)) != sizeof(value)) { + LOGE("Failure writing event: %s\n", strerror(errno)); + } + int8_t response; + if (read(pipeC, &response, sizeof(response)) != sizeof(response)) { + LOGE("Failure reading response: %s\n", strerror(errno)); + } +} + +static void onDestroy(ANativeActivity* activity) { + LOGV("onDestroy called"); + NativeActivityEvent event = { DESTROY }; + putEventSynchronously(&event); +} + +static void onStart(ANativeActivity* activity) { + LOGV("onStart called"); + NativeActivityEvent event = { START }; + putEventSynchronously(&event); +} + +static void onResume(ANativeActivity* activity) { + LOGV("onResume called"); + NativeActivitySaveStateEvent event = { RESUME }; + putEventSynchronously(&event); +} + +static void* onSaveInstanceState(ANativeActivity* activity, size_t* outLen) { + LOGV("onSaveInstanceState called"); + NativeActivitySaveStateEvent event = { SAVE_INSTANCE_STATE }; + putEventSynchronously(&event); + *outLen = event.savedStateSize; + return event.savedState; +} + +static void onPause(ANativeActivity* activity) { + LOGV("onPause called"); + NativeActivityEvent event = { PAUSE }; + putEventSynchronously(&event); +} + +static void onStop(ANativeActivity* activity) { + LOGV("onStop called"); + NativeActivityEvent event = { STOP }; + putEventSynchronously(&event); +} + +static void onConfigurationChanged(ANativeActivity* activity) { + LOGV("onConfigurationChanged called"); + NativeActivityEvent event = { CONFIGURATION_CHANGED }; + putEventSynchronously(&event); +} + +static void onLowMemory(ANativeActivity* activity) { + LOGV("onLowMemory called"); + NativeActivityEvent event = { LOW_MEMORY }; + putEventSynchronously(&event); +} + +static void onWindowFocusChanged(ANativeActivity* activity, int focused) { + LOGV("onWindowFocusChanged called"); + NativeActivityEvent event = { focused ? WINDOW_GAINED_FOCUS : WINDOW_LOST_FOCUS }; + putEventSynchronously(&event); +} + +static void onNativeWindowCreated(ANativeActivity* activity, ANativeWindow* window) { + LOGV("onNativeWindowCreated called"); + NativeActivityWindowEvent event = { NATIVE_WINDOW_CREATED, window }; + putEventSynchronously(&event); +} + +static void onNativeWindowDestroyed(ANativeActivity* activity, ANativeWindow* window) { + LOGV("onNativeWindowDestroyed called"); + NativeActivityWindowEvent event = { NATIVE_WINDOW_DESTROYED, window }; + putEventSynchronously(&event); +} + +static void onInputQueueCreated(ANativeActivity* activity, AInputQueue* queue) { + LOGV("onInputQueueCreated called"); + NativeActivityQueueEvent event = { INPUT_QUEUE_CREATED, queue }; + putEventSynchronously(&event); +} + +static void onInputQueueDestroyed(ANativeActivity* activity, AInputQueue* queue) { + LOGV("onInputQueueDestroyed called"); + NativeActivityQueueEvent event = { INPUT_QUEUE_DESTROYED, queue }; + putEventSynchronously(&event); +} + +// ANativeActivity_onCreate. +extern "C" void Konan_main(ANativeActivity* activity, void* savedState, size_t savedStateSize) { + nativeActivityState = {activity, savedState, savedStateSize}; + + activity->callbacks->onDestroy = onDestroy; + activity->callbacks->onStart = onStart; + activity->callbacks->onResume = onResume; + activity->callbacks->onSaveInstanceState = onSaveInstanceState; + activity->callbacks->onPause = onPause; + activity->callbacks->onStop = onStop; + activity->callbacks->onConfigurationChanged = onConfigurationChanged; + activity->callbacks->onLowMemory = onLowMemory; + activity->callbacks->onWindowFocusChanged = onWindowFocusChanged; + activity->callbacks->onNativeWindowCreated = onNativeWindowCreated; + activity->callbacks->onNativeWindowDestroyed = onNativeWindowDestroyed; + activity->callbacks->onInputQueueCreated = onInputQueueCreated; + activity->callbacks->onInputQueueDestroyed = onInputQueueDestroyed; + + runKonan_start(); +} + +#endif \ No newline at end of file diff --git a/runtime/src/launcher/cpp/androidLauncher.h b/runtime/src/launcher/cpp/androidLauncher.h new file mode 100644 index 00000000000..4e6ff4b405a --- /dev/null +++ b/runtime/src/launcher/cpp/androidLauncher.h @@ -0,0 +1,85 @@ +/* + * Copyright 2010-2017 JetBrains s.r.o. + * + * 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. + */ + +#ifndef ANDROID_LAUNCHER_H +#define ANDROID_LAUNCHER_H + +#include + +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +struct NativeActivityState { + struct ANativeActivity* activity; + void* savedState; + size_t savedStateSize; + struct ALooper* looper; +}; + +void getNativeActivityState(struct NativeActivityState* state); + +void notifySysEventProcessed(int fd); + +#define LOOPER_ID_SYS 1 + +typedef enum NativeActivityEventKind { + UNKNOWN, + DESTROY, + START, + RESUME, + SAVE_INSTANCE_STATE, + PAUSE, + STOP, + CONFIGURATION_CHANGED, + LOW_MEMORY, + WINDOW_GAINED_FOCUS, + WINDOW_LOST_FOCUS, + NATIVE_WINDOW_CREATED, + NATIVE_WINDOW_DESTROYED, + INPUT_QUEUE_CREATED, + INPUT_QUEUE_DESTROYED +} NativeActivityEventKind; + +struct NativeActivityEvent { + NativeActivityEventKind eventKind; +}; + +struct NativeActivitySaveStateEvent { + NativeActivityEventKind eventKind; + void* savedState; + size_t savedStateSize; +}; + +struct NativeActivityWindowEvent { + NativeActivityEventKind eventKind; + struct ANativeWindow* window; +}; + +struct NativeActivityQueueEvent { + NativeActivityEventKind eventKind; + struct AInputQueue* queue; +}; + +#ifdef __cplusplus +} +#endif + +#endif // ANDROID_LAUNCHER_H \ No newline at end of file diff --git a/runtime/src/launcher/cpp/launcher.cpp b/runtime/src/launcher/cpp/launcher.cpp index d19fb664b3a..4b73b97397e 100644 --- a/runtime/src/launcher/cpp/launcher.cpp +++ b/runtime/src/launcher/cpp/launcher.cpp @@ -20,6 +20,8 @@ #include "KString.h" #include "Types.h" +#ifndef ANDROID + //--- Setup args --------------------------------------------------------------// OBJ_GETTER(setupArgs, int argc, const char** argv) { @@ -54,3 +56,5 @@ extern "C" int Konan_main(int argc, const char** argv) { return exitStatus; } + +#endif diff --git a/runtime/src/main/cpp/KString.cpp b/runtime/src/main/cpp/KString.cpp index 16b9da4209d..c54c40790db 100644 --- a/runtime/src/main/cpp/KString.cpp +++ b/runtime/src/main/cpp/KString.cpp @@ -34,6 +34,10 @@ #include "utf8.h" +#ifdef ANDROID +#include +#endif + namespace { OBJ_GETTER(utf8ToUtf16, const char* rawString, size_t rawStringLength) { @@ -1129,7 +1133,11 @@ void Kotlin_io_Console_print(KString message) { const KChar* utf16 = CharArrayAddressOfElementAt(message, 0); std::string utf8; utf8::utf16to8(utf16, utf16 + message->count_, back_inserter(utf8)); + #ifdef ANDROID + __android_log_print(ANDROID_LOG_INFO, "Konan_main", "%s", utf8.c_str()); + #else write(STDOUT_FILENO, utf8.c_str(), utf8.size()); + #endif } void Kotlin_io_Console_println(KString message) { @@ -1138,7 +1146,11 @@ void Kotlin_io_Console_println(KString message) { } void Kotlin_io_Console_println0() { + #ifdef ANDROID + __android_log_print(ANDROID_LOG_INFO, "Konan_main", "\n"); + #else write(STDOUT_FILENO, "\n", 1); + #endif } OBJ_GETTER0(Kotlin_io_Console_readLine) {