Search code examples
androidc++android-ndk

Android NDK: Failed to call C++ constructor


I'm trying to port a C++ desktop program to Android using NDK. When Debugging I found that the constructor of class Constants is not called when initializing class Windows, leaving width_ and height_ to 0, and the call trace is weird. enter image description here

Debug line:
https://github.com/speedyHKjournalist/OpenMapleClient/blob/main/app/src/main/cpp/src/IO/Window.cpp#L34

From trace it seems that Error Game::init(android_app *pApp) is not called ?
Trace:

(lldb) thread backtrace
* thread #1, name = 'ri0.glfwexample', stop reason = step over
  * frame #0: 0x0000007535ddfd70 libglfw-example.so`ms::Window::Window(this=0x00000075360ba990) at Window.cpp:34:21
    frame #1: 0x0000007535b5fad8 libglfw-example.so`::__cxx_global_var_init.10() at Singleton.h:33:17
    frame #2: 0x000000766d648bb8 linker64`__dl__ZN6soinfo17call_constructorsEv + 632
    frame #3: 0x000000766d63301c linker64`__dl__Z9do_dlopenPKciPK17android_dlextinfoPKv + 2288
    frame #4: 0x000000766d62e100 linker64`__dl___loader_android_dlopen_ext + 88
    frame #5: 0x00000076561bc110 libdl.so`android_dlopen_ext + 24
    frame #6: 0x000000766b9243dc libnativeloader.so`android::NativeLoaderNamespace::Load(char const*) const + 200
    frame #7: 0x000000766b914e74 libnativeloader.so`OpenNativeLibraryInNamespace + 72
    frame #8: 0x000000766b91459c libnativeloader.so`OpenNativeLibrary + 140
    frame #9: 0x000000765191ae00 libandroid_runtime.so`android::loadNativeCode_native(_JNIEnv*, _jobject*, _jstring*, _jstring*, _jobject*, _jstring*, _jstring*, _jstring*, int, _jobject*, _jbyteArray*, _jobject*, _jstring*) + 308
    frame #10: 0x00000000721bec14 boot-framework.oat`art_jni_trampoline + 308
    frame #11: 0x00000075c0e18968 libart.so`art_quick_invoke_stub + 552
    frame #12: 0x00000075c0e85ff4 libart.so`art::ArtMethod::Invoke(art::Thread*, unsigned int*, unsigned int, art::JValue*, char const*) + 196
    frame #13: 0x00000075c0fea3ec libart.so`art::interpreter::ArtInterpreterToCompiledCodeBridge(art::Thread*, art::ArtMethod*, art::ShadowFrame*, unsigned short, art::JValue*) + 408
    frame #14: 0x00000075c0fe618c libart.so`bool art::interpreter::DoCall<true, false>(art::ArtMethod*, art::Thread*, art::ShadowFrame&, art::Instruction const*, unsigned short, art::JValue*) + 708
    frame #15: 0x00000075c0e2cd38 libart.so`void art::interpreter::ExecuteSwitchImplCpp<false, false>(art::interpreter::SwitchImplContext*) + 23432
    frame #16: 0x00000075c0e24bdc libart.so`ExecuteSwitchImplAsm + 12
    frame #17: 0x00000075c0fe4934 libart.so`art::interpreter::ExecuteSwitch(art::Thread*, art::CodeItemDataAccessor const&, art::ShadowFrame&, art::JValue, bool) + 324
    frame #18: 0x00000075c0fdccd4 libart.so`art::interpreter::Execute(art::Thread*, art::CodeItemDataAccessor const&, art::ShadowFrame&, art::JValue, bool, bool) + 224
    frame #19: 0x00000075c0fe44a8 libart.so`art::interpreter::ArtInterpreterToInterpreterBridge(art::Thread*, art::CodeItemDataAccessor const&, art::ShadowFrame*, art::JValue*) + 212
    frame #20: 0x00000075c0fe6170 libart.so`bool art::interpreter::DoCall<true, false>(art::ArtMethod*, art::Thread*, art::ShadowFrame&, art::Instruction const*, unsigned short, art::JValue*) + 680
    frame #21: 0x00000075c0e2dc40 libart.so`void art::interpreter::ExecuteSwitchImplCpp<false, false>(art::interpreter::SwitchImplContext*) + 27280
    frame #22: 0x00000075c0e24bdc libart.so`ExecuteSwitchImplAsm + 12
    frame #23: 0x00000075c0fe4934 libart.so`art::interpreter::ExecuteSwitch(art::Thread*, art::CodeItemDataAccessor const&, art::ShadowFrame&, art::JValue, bool) + 324
    frame #24: 0x00000075c0fdccd4 libart.so`art::interpreter::Execute(art::Thread*, art::CodeItemDataAccessor const&, art::ShadowFrame&, art::JValue, bool, bool) + 224
    frame #25: 0x00000075c0fe44a8 libart.so`art::interpreter::ArtInterpreterToInterpreterBridge(art::Thread*, art::CodeItemDataAccessor const&, art::ShadowFrame*, art::JValue*) + 212
    frame #26: 0x00000075c0fe4f64 libart.so`bool art::interpreter::DoCall<false, false>(art::ArtMethod*, art::Thread*, art::ShadowFrame&, art::Instruction const*, unsigned short, art::JValue*) + 796
    frame #27: 0x00000075c0e2dc70 libart.so`void art::interpreter::ExecuteSwitchImplCpp<false, false>(art::interpreter::SwitchImplContext*) + 27328
    frame #28: 0x00000075c0e24bdc libart.so`ExecuteSwitchImplAsm + 12
    frame #29: 0x00000075c0fe4934 libart.so`art::interpreter::ExecuteSwitch(art::Thread*, art::CodeItemDataAccessor const&, art::ShadowFrame&, art::JValue, bool) + 324
    frame #30: 0x00000075c0fdccd4 libart.so`art::interpreter::Execute(art::Thread*, art::CodeItemDataAccessor const&, art::ShadowFrame&, art::JValue, bool, bool) + 224
    frame #31: 0x00000075c0fe44a8 libart.so`art::interpreter::ArtInterpreterToInterpreterBridge(art::Thread*, art::CodeItemDataAccessor const&, art::ShadowFrame*, art::JValue*) + 212
    frame #32: 0x00000075c0fe4f64 libart.so`bool art::interpreter::DoCall<false, false>(art::ArtMethod*, art::Thread*, art::ShadowFrame&, art::Instruction const*, unsigned short, art::JValue*) + 796
    frame #33: 0x00000075c0e2dc70 libart.so`void art::interpreter::ExecuteSwitchImplCpp<false, false>(art::interpreter::SwitchImplContext*) + 27328
    frame #34: 0x00000075c0e24bdc libart.so`ExecuteSwitchImplAsm + 12
    frame #35: 0x00000075c0fe4934 libart.so`art::interpreter::ExecuteSwitch(art::Thread*, art::CodeItemDataAccessor const&, art::ShadowFrame&, art::JValue, bool) + 324
    frame #36: 0x00000075c0fdccd4 libart.so`art::interpreter::Execute(art::Thread*, art::CodeItemDataAccessor const&, art::ShadowFrame&, art::JValue, bool, bool) + 224
    frame #37: 0x00000075c0fe44a8 libart.so`art::interpreter::ArtInterpreterToInterpreterBridge(art::Thread*, art::CodeItemDataAccessor const&, art::ShadowFrame*, art::JValue*) + 212
    frame #38: 0x00000075c0fe5964 libart.so`bool art::interpreter::DoCall<false, true>(art::ArtMethod*, art::Thread*, art::ShadowFrame&, art::Instruction const*, unsigned short, art::JValue*) + 1704
    frame #39: 0x00000075c0e54774 libart.so`void art::interpreter::ExecuteSwitchImplCpp<true, false>(art::interpreter::SwitchImplContext*) + 47036
    frame #40: 0x00000075c0e24bdc libart.so`ExecuteSwitchImplAsm + 12
    frame #41: 0x00000075c0fe4934 libart.so`art::interpreter::ExecuteSwitch(art::Thread*, art::CodeItemDataAccessor const&, art::ShadowFrame&, art::JValue, bool) + 324
    frame #42: 0x00000075c0fdccd4 libart.so`art::interpreter::Execute(art::Thread*, art::CodeItemDataAccessor const&, art::ShadowFrame&, art::JValue, bool, bool) + 224
    frame #43: 0x00000075c0fe44a8 libart.so`art::interpreter::ArtInterpreterToInterpreterBridge(art::Thread*, art::CodeItemDataAccessor const&, art::ShadowFrame*, art::JValue*) + 212
    frame #44: 0x00000075c0fe5964 libart.so`bool art::interpreter::DoCall<false, true>(art::ArtMethod*, art::Thread*, art::ShadowFrame&, art::Instruction const*, unsigned short, art::JValue*) + 1704
    frame #45: 0x00000075c0e52350 libart.so`void art::interpreter::ExecuteSwitchImplCpp<true, false>(art::interpreter::SwitchImplContext*) + 37784
    frame #46: 0x00000075c0e24bdc libart.so`ExecuteSwitchImplAsm + 12
    frame #47: 0x00000075c0fe4934 libart.so`art::interpreter::ExecuteSwitch(art::Thread*, art::CodeItemDataAccessor const&, art::ShadowFrame&, art::JValue, bool) + 324
    frame #48: 0x00000075c0fdccd4 libart.so`art::interpreter::Execute(art::Thread*, art::CodeItemDataAccessor const&, art::ShadowFrame&, art::JValue, bool, bool) + 224
    frame #49: 0x00000075c0fe44a8 libart.so`art::interpreter::ArtInterpreterToInterpreterBridge(art::Thread*, art::CodeItemDataAccessor const&, art::ShadowFrame*, art::JValue*) + 212
    frame #50: 0x00000075c0fe4f64 libart.so`bool art::interpreter::DoCall<false, false>(art::ArtMethod*, art::Thread*, art::ShadowFrame&, art::Instruction const*, unsigned short, art::JValue*) + 796
    frame #51: 0x00000075c0e2dc70 libart.so`void art::interpreter::ExecuteSwitchImplCpp<false, false>(art::interpreter::SwitchImplContext*) + 27328
    frame #52: 0x00000075c0e24bdc libart.so`ExecuteSwitchImplAsm + 12
    frame #53: 0x00000075c0fe4934 libart.so`art::interpreter::ExecuteSwitch(art::Thread*, art::CodeItemDataAccessor const&, art::ShadowFrame&, art::JValue, bool) + 324
    frame #54: 0x00000075c0fdccd4 libart.so`art::interpreter::Execute(art::Thread*, art::CodeItemDataAccessor const&, art::ShadowFrame&, art::JValue, bool, bool) + 224
    frame #55: 0x00000075c0fe44a8 libart.so`art::interpreter::ArtInterpreterToInterpreterBridge(art::Thread*, art::CodeItemDataAccessor const&, art::ShadowFrame*, art::JValue*) + 212
    frame #56: 0x00000075c0fe4f64 libart.so`bool art::interpreter::DoCall<false, false>(art::ArtMethod*, art::Thread*, art::ShadowFrame&, art::Instruction const*, unsigned short, art::JValue*) + 796
    frame #57: 0x00000075c0e2dc70 libart.so`void art::interpreter::ExecuteSwitchImplCpp<false, false>(art::interpreter::SwitchImplContext*) + 27328
    frame #58: 0x00000075c0e24bdc libart.so`ExecuteSwitchImplAsm + 12
    frame #59: 0x00000075c0fe4934 libart.so`art::interpreter::ExecuteSwitch(art::Thread*, art::CodeItemDataAccessor const&, art::ShadowFrame&, art::JValue, bool) + 324
    frame #60: 0x00000075c0fdccd4 libart.so`art::interpreter::Execute(art::Thread*, art::CodeItemDataAccessor const&, art::ShadowFrame&, art::JValue, bool, bool) + 224
    frame #61: 0x00000075c0fe44a8 libart.so`art::interpreter::ArtInterpreterToInterpreterBridge(art::Thread*, art::CodeItemDataAccessor const&, art::ShadowFrame*, art::JValue*) + 212
    frame #62: 0x00000075c0fe4f64 libart.so`bool art::interpreter::DoCall<false, false>(art::ArtMethod*, art::Thread*, art::ShadowFrame&, art::Instruction const*, unsigned short, art::JValue*) + 796
    frame #63: 0x00000075c0e2dc70 libart.so`void art::interpreter::ExecuteSwitchImplCpp<false, false>(art::interpreter::SwitchImplContext*) + 27328
    frame #64: 0x00000075c0e24bdc libart.so`ExecuteSwitchImplAsm + 12
    frame #65: 0x00000075c0fe4934 libart.so`art::interpreter::ExecuteSwitch(art::Thread*, art::CodeItemDataAccessor const&, art::ShadowFrame&, art::JValue, bool) + 324
    frame #66: 0x00000075c0fdccd4 libart.so`art::interpreter::Execute(art::Thread*, art::CodeItemDataAccessor const&, art::ShadowFrame&, art::JValue, bool, bool) + 224
    frame #67: 0x00000075c0fe44a8 libart.so`art::interpreter::ArtInterpreterToInterpreterBridge(art::Thread*, art::CodeItemDataAccessor const&, art::ShadowFrame*, art::JValue*) + 212
    frame #68: 0x00000075c0fe4f64 libart.so`bool art::interpreter::DoCall<false, false>(art::ArtMethod*, art::Thread*, art::ShadowFrame&, art::Instruction const*, unsigned short, art::JValue*) + 796
    frame #69: 0x00000075c0e2dc70 libart.so`void art::interpreter::ExecuteSwitchImplCpp<false, false>(art::interpreter::SwitchImplContext*) + 27328
    frame #70: 0x00000075c0e24bdc libart.so`ExecuteSwitchImplAsm + 12
    frame #71: 0x00000075c0fe4934 libart.so`art::interpreter::ExecuteSwitch(art::Thread*, art::CodeItemDataAccessor const&, art::ShadowFrame&, art::JValue, bool) + 324
    frame #72: 0x00000075c0fdccd4 libart.so`art::interpreter::Execute(art::Thread*, art::CodeItemDataAccessor const&, art::ShadowFrame&, art::JValue, bool, bool) + 224
    frame #73: 0x00000075c0fe44a8 libart.so`art::interpreter::ArtInterpreterToInterpreterBridge(art::Thread*, art::CodeItemDataAccessor const&, art::ShadowFrame*, art::JValue*) + 212
    frame #74: 0x00000075c0fe4f64 libart.so`bool art::interpreter::DoCall<false, false>(art::ArtMethod*, art::Thread*, art::ShadowFrame&, art::Instruction const*, unsigned short, art::JValue*) + 796
    frame #75: 0x00000075c0e2dc70 libart.so`void art::interpreter::ExecuteSwitchImplCpp<false, false>(art::interpreter::SwitchImplContext*) + 27328
    frame #76: 0x00000075c0e24bdc libart.so`ExecuteSwitchImplAsm + 12
    frame #77: 0x00000075c0fe4934 libart.so`art::interpreter::ExecuteSwitch(art::Thread*, art::CodeItemDataAccessor const&, art::ShadowFrame&, art::JValue, bool) + 324
    frame #78: 0x00000075c0fdccd4 libart.so`art::interpreter::Execute(art::Thread*, art::CodeItemDataAccessor const&, art::ShadowFrame&, art::JValue, bool, bool) + 224
    frame #79: 0x00000075c0fe44a8 libart.so`art::interpreter::ArtInterpreterToInterpreterBridge(art::Thread*, art::CodeItemDataAccessor const&, art::ShadowFrame*, art::JValue*) + 212
    frame #80: 0x00000075c0fe4f64 libart.so`bool art::interpreter::DoCall<false, false>(art::ArtMethod*, art::Thread*, art::ShadowFrame&, art::Instruction const*, unsigned short, art::JValue*) + 796
    frame #81: 0x00000075c0e2dc70 libart.so`void art::interpreter::ExecuteSwitchImplCpp<false, false>(art::interpreter::SwitchImplContext*) + 27328
    frame #82: 0x00000075c0e24bdc libart.so`ExecuteSwitchImplAsm + 12
    frame #83: 0x00000075c0fe4934 libart.so`art::interpreter::ExecuteSwitch(art::Thread*, art::CodeItemDataAccessor const&, art::ShadowFrame&, art::JValue, bool) + 324
    frame #84: 0x00000075c0fdccd4 libart.so`art::interpreter::Execute(art::Thread*, art::CodeItemDataAccessor const&, art::ShadowFrame&, art::JValue, bool, bool) + 224
    frame #85: 0x00000075c0fe44a8 libart.so`art::interpreter::ArtInterpreterToInterpreterBridge(art::Thread*, art::CodeItemDataAccessor const&, art::ShadowFrame*, art::JValue*) + 212
    frame #86: 0x00000075c0fe4f64 libart.so`bool art::interpreter::DoCall<false, false>(art::ArtMethod*, art::Thread*, art::ShadowFrame&, art::Instruction const*, unsigned short, art::JValue*) + 796
    frame #87: 0x00000075c0e2ce70 libart.so`void art::interpreter::ExecuteSwitchImplCpp<false, false>(art::interpreter::SwitchImplContext*) + 23744
    frame #88: 0x00000075c0e24bdc libart.so`ExecuteSwitchImplAsm + 12
    frame #89: 0x00000075c136b554 libart.so`MterpInvokeStatic + 2552
    frame #90: 0x00000075c0e03998 libart.so`mterp_op_invoke_static + 24
    frame #91: 0x00000075c0fdcd30 libart.so`art::interpreter::Execute(art::Thread*, art::CodeItemDataAccessor const&, art::ShadowFrame&, art::JValue, bool, bool) + 316
    frame #92: 0x00000075c134e560 libart.so`artQuickToInterpreterBridge + 784
    frame #93: 0x00000075c0e2237c libart.so`art_quick_to_interpreter_bridge + 92
    frame #94: 0x00000075c0e22590 libart.so

Solution

  • As @user17732522 correctly pointed out you have no guarantees on the initialization order.

    So I'd change Singleton class as follows:

    template<class T>
    class Singleton {
    public:
        virtual ~Singleton() = default;
    
        static T &get() { 
            static T instance_;
            return instance_;
        }
    
    private:
        T &operator=(const T &) = delete;
    };
    
    // No need for the code above
    // template<class T>
    // T Singleton<T>::instance_;