I made a c++ main aplication that loads a so library also made by me.
Both sources shares a common header (TestFlags.h).
Inside TestFlags.h I have an class and a pointer declaration of it which is intended to be global to the whole application, that is define a instance in the main app and use it inside a library function.
class TestFlags {
public:
TestFlags() : behaviour(1)
{}
int behaviour;
};
extern __attribute__ ((visibility("default"))) TestFlags * gpTestFlags;
then a sequence of execution steps followed to reach the named goal are:
main application creates a new instance of TestFlags ---> gpTestFlags = new TestFlags();
main application load the library ---> dlopen(library.so, RTLD_LAZY|RTLD_GLOBAL)
invoke a function that resides inside the library which uses previous instance declared ---> gpTestFlags->behaviour = 2;
Received a SIGSEGV: Segmentation fault because gpTestFlags is NULL
It seems that inside the library gpTestFlags instance is not seen for some reason.
Same thing also happens with other static class I have, values which are configured on the main application not seen inside the library.
As far I can research it seems that the library manages a totally different memory space for those declarations like if it was duplicated.
This is the expected way dlopen() would work.
The two modules have independent global symbols called gpTestFlags. If you try to link them together, the linker would scream about duplicates.
You can declare the pointer in library as weak, or you can use dlsym() to resolve the linkage programmatically.
Related
I have a JNI function in a C++ library.
When I create the library using cmake (but forget to put function declaration) in the header file, the library is created successfully.
When I look for function name in library symbol table I get following output
nm libuserlibrary.so | grep printxx
00506e60 T _Z60Java_com_example_user_myapplication_userlibrary_printxxP7JNIEnv_P8_jobject
But when I give function declaration in the header file, I get following output
nm libuserlibrary.so | grep printxx
00506e50 T Java_com_example_user_myapplication_userlibrary_printxx
Why is there this difference between these two symbol table entries? What is the purpose of _Z60 and P7JNIEnv_P8_jobject around the function name?
I also noticed that in the first case, I cannot call the JNI funciton from Android java code (it says unsatisfied-linker-error, implementation not found).
C++ allows function overloads and namespaces like Java does. So, it annotated the function name with parameter information so the linker can bind to the correct overload.
JNI was designed for C which does not allow function overloads or namespaces. So it invented it's own annotation system and provides the javah tool to help you use it. The header can be used in C++ too. C++ was designed to allow some functions to be called as if they written in C. The header has code that indicates that to the compiler. So, put it all together and you can write Java-callable functions in C++.
I'm interested in understanding how a dex file (classesN.dex) references methods in another classesN.dex file.
In a standard dex layout, you have all of the class, method, type, etc... definitions in different tables. Things that are dynamically linked (such as those from the Android framework) simply have their method prototypes included, but no code data. Is it true that in a multidex setup, each classesN.dex contains a set of class implementations, and methods that are implemented in other dex files are merely included in the same way as dynamically linked calls?
In other words, if classes.dex needs to reference a method classes1.dex, it will include that method as a prototype within classes.dex, and then include its implementation in classes1.dex?
I ended up solving this question: it turns out that in a multidex layout the relevant method and class definitions are included in each dex file. For example, if classes.dex references methods foo() from classes1.dex, it will include a relevant entry in the method table for foo() within classes.dex's method table. But the implementation of foo() will appear in classes1.dex. This works because foo() is usually something like the entry of a library used by the app. The entry points of that library can be used without all of the methods called by foo. In classes.dex, foo will be defined without a corresponding code item, just as if it were a part of the dynamically linked Android standard library.
I have two app projects, A and B, based on a library project C.
All the java code is contained by library project C. Projects A and B only differ in their AndroidManifests, varying their functionality through setting different flag variables.
To give a simplified example, A gives access to a class ImportExport, and its method ImportExport.import(). The other, app B, doesn't give access to such functionaliy.
I would like to make the ImportExport.import() code nonexistent in the compiled app B. Is there a way I could add an empty ImportExport.import() method definition to app B, that would override the library's definition of ImportExport.import()?
If necessary, I'm also happy with overriding the whole class ImportExport.
I have a library that I want to customize its work (I mean replacing the main of the library by my outside program so I can for example reorder the calls of the library's functions) and for that I had to change some static variable to extern variables so the library and my program can handle them both.
My program works fine when on run on my Linux desktop machine, however when I tried to port that to Android using NDK, I couldn't compile it because of the extern keyword .
So, I was wondering if there's a way concerning the Android.mk or alternative to the use of extern keyword, to make the things work.
You're getting an "undefined reference" because extern is not a variable definition, only a declaration. That means you must have an non-extern declation somewhere else in your code, otherwise the compiler doesn't allocate a symbol for your variable.
As for alternatives, no, an extern variable is the only way to have a global variable accross multiple object files in C.
If you only need a global variable in the same object file, you can use static so the symbol is not exported to other objects.
I make sereval Android apps with similar code, but I need to stay flexible for customizing the apps. My solution right now is, that I have a Library-Project, where I can override functionality in the Project by extending classes. For the following example, I call the Library Project PL. P1 is a customized Project using PL and P2 is another customized Project using PL.
My Problem is now, that in PL I would like to make an instance from StudentPL.java. In P1, there is no need to make any changes to StudentPL, so the compiler should take this class, but in P2, there I have StudentP2.java, that extends from StudentPL.java. So the instance made in PL, should be an instance of StudentP2.java.
My idea was now, that I make a package called mirror, that is directly in the src-Folder of the Project PL. There I make the class mirror.Student.java that extends from StudentPL.java. In the Library-Project, I make now an instance of Student.java. For Project P1, there are no changes needed. In P2 I make the same folder mirror in src Folder and I make the same class mirror.Student.java that extends from StudentP2.java now. The Idea is, that the ClassLoader now loads mirror.Student.java from P2 and ignores mirror.Student.java from PL, but this results in the following error:
Dex Loader] Unable to execute dex: Multiple dex files define Lmirror/Student;
Conversion to Dalvik format failed: Unable to execute dex: Multiple dex files define Lmirror/Student
Here is a UML of what I'm talking about:
http://www.koenix-band.ch/images/other/Stackoverflow.gif
Maybe I should overwrite the ClassLoader, but I have no idea how to do this? Does anyone have an idea to solve this problem? Maybe someone has another idea, how i could customize the apps.
Michael
In my opinion it would be better to make your MainActivityPL abstract with a setStudent or similar method. The bulk of the activity and all its logic would still be shared from your library, but it would allow your other projects an option to use different student objects by extending the StudentPL class.