mirror of
https://gitlab.com/freepascal.org/fpc/source.git
synced 2025-08-12 04:06:08 +02:00
* android: Android versions prior to 4.1 do not support recursive dlopen() calls.
Therefore if a shared library is loaded by JVM ( using dlopen() ), it is not possible to use dlopen() in a units initialization code - dlopen() simply hangs. To workaround this issue, if a library exports JNI_OnLoad(), then no unit initialization is performed during library load. The initialization is called when JVM has loaded the library and calls JNI_OnLoad(). git-svn-id: trunk@34406 -
This commit is contained in:
parent
649823a246
commit
a0d6873331
@ -36,8 +36,13 @@ interface
|
||||
procedure generatelib;override;
|
||||
end;
|
||||
|
||||
{ texportlibandroid }
|
||||
|
||||
texportlibandroid=class(texportlibunix)
|
||||
public
|
||||
procedure setfininame(list: TAsmList; const s: string); override;
|
||||
procedure exportprocedure(hp: texported_item); override;
|
||||
procedure generatelib; override;
|
||||
end;
|
||||
|
||||
{ tlinkerandroid }
|
||||
@ -46,6 +51,7 @@ interface
|
||||
private
|
||||
prtobj : string[80];
|
||||
reorder : boolean;
|
||||
FJNIOnLoadDef: tprocdef;
|
||||
Function WriteResponseFile(isdll:boolean) : Boolean;
|
||||
function DoLink(IsSharedLib: boolean): boolean;
|
||||
public
|
||||
@ -66,12 +72,15 @@ implementation
|
||||
verbose,systems,globtype,globals,
|
||||
symconst,script,
|
||||
fmodule,
|
||||
aasmbase,aasmtai,aasmcpu,cpubase,
|
||||
aasmbase,aasmtai,aasmcpu,cpubase,hlcgcpu,hlcgobj,
|
||||
cgbase,cgobj,cgutils,ogbase,ncgutil,
|
||||
comprsrc,
|
||||
rescmn, i_android
|
||||
;
|
||||
|
||||
const
|
||||
SJNI_OnLoad = 'JNI_OnLoad';
|
||||
|
||||
{*****************************************************************************
|
||||
TIMPORTLIBANDROID
|
||||
*****************************************************************************}
|
||||
@ -103,6 +112,44 @@ implementation
|
||||
inherited setfininame(list,s);
|
||||
end;
|
||||
|
||||
procedure texportlibandroid.exportprocedure(hp: texported_item);
|
||||
begin
|
||||
{
|
||||
Android versions prior to 4.1 do not support recursive dlopen() calls.
|
||||
Therefore if a shared library is loaded by JVM ( using dlopen() ),
|
||||
it is not possible to use dlopen() in a units initialization code -
|
||||
dlopen() simply hangs.
|
||||
To workaround this issue, if a library exports JNI_OnLoad(), then
|
||||
no unit initialization is performed during library load.
|
||||
The initialization is called when JVM has loaded the library and calls
|
||||
JNI_OnLoad().
|
||||
}
|
||||
// Check for the JNI_OnLoad export
|
||||
if current_module.islibrary and not hp.is_var and assigned(hp.sym) and
|
||||
(hp.sym.typ = procsym) and (eo_name in hp.options) and
|
||||
(hp.name^ = SJNI_OnLoad) and (tprocsym(hp.sym).procdeflist.count = 1) then
|
||||
begin
|
||||
// Save the JNI_OnLoad procdef
|
||||
tlinkerandroid(Linker).FJNIOnLoadDef:=tprocdef(tprocsym(hp.sym).procdeflist[0]);;
|
||||
hp.Free;
|
||||
exit;
|
||||
end;
|
||||
inherited exportprocedure(hp);
|
||||
end;
|
||||
|
||||
procedure texportlibandroid.generatelib;
|
||||
begin
|
||||
inherited generatelib;
|
||||
if tlinkerandroid(Linker).FJNIOnLoadDef = nil then
|
||||
exit;
|
||||
// If JNI_OnLoad is exported, export a system proxy function instead
|
||||
create_hlcodegen;
|
||||
new_section(current_asmdata.asmlists[al_procedures],sec_code,'',0);
|
||||
hlcg.g_external_wrapper(current_asmdata.asmlists[al_procedures],nil,SJNI_OnLoad,'FPC_JNI_ON_LOAD_PROXY',true);
|
||||
destroy_hlcodegen;
|
||||
exportedsymnames.insert(SJNI_OnLoad);
|
||||
end;
|
||||
|
||||
{*****************************************************************************
|
||||
TLINKERANDROID
|
||||
*****************************************************************************}
|
||||
@ -304,6 +351,20 @@ begin
|
||||
add('}');
|
||||
add('INSERT BEFORE .data1');
|
||||
|
||||
// Define different aliases for normal and JNI libraries
|
||||
if FJNIOnLoadDef <> nil then
|
||||
begin
|
||||
s:=FJNIOnLoadDef.mangledname;
|
||||
s1:='FPC_JNI_LIB_MAIN_ANDROID';
|
||||
end
|
||||
else
|
||||
begin
|
||||
s:='0';
|
||||
s1:='PASCALMAIN';
|
||||
end;
|
||||
add('FPC_JNI_ON_LOAD = ' + s + ';');
|
||||
add('FPC_LIB_MAIN_ANDROID = ' + s1 + ';');
|
||||
|
||||
{ Write and Close response }
|
||||
writetodisk;
|
||||
Free;
|
||||
|
@ -47,7 +47,7 @@ FPC_SHARED_LIB_START:
|
||||
str r0,[ip]
|
||||
|
||||
/* Call main */
|
||||
blx PASCALMAIN
|
||||
blx FPC_LIB_MAIN_ANDROID
|
||||
/* Call library init */
|
||||
blx FPC_LIB_INIT_ANDROID
|
||||
|
||||
|
@ -51,7 +51,7 @@ env_ok:
|
||||
popl %ebx
|
||||
|
||||
/* Call main */
|
||||
call PASCALMAIN@PLT
|
||||
call FPC_LIB_MAIN_ANDROID@PLT
|
||||
/* Call library init */
|
||||
call FPC_LIB_INIT_ANDROID@PLT
|
||||
|
||||
|
@ -44,7 +44,7 @@ GotEnv:
|
||||
sw $t0, ($t1)
|
||||
|
||||
/* Call main */
|
||||
jal PASCALMAIN
|
||||
jal FPC_LIB_MAIN_ANDROID
|
||||
nop
|
||||
/* Call library init */
|
||||
jal FPC_LIB_INIT_ANDROID
|
||||
|
@ -49,7 +49,7 @@ begin
|
||||
{ Starting from Android 4.4 stdio handles are closed by libc prior to calling
|
||||
finalization routines of shared libraries. This causes a error while trying to
|
||||
writeln during library finalization and finally a crash because the error can
|
||||
not be printer too.
|
||||
not be printed too.
|
||||
It is needed to save stdout and stderr handles by duplicating them and restore
|
||||
them before library finalization.
|
||||
}
|
||||
@ -206,12 +206,34 @@ begin
|
||||
DefaultLogTag[len + 1]:=#0;
|
||||
end;
|
||||
|
||||
// ************* JNI init
|
||||
|
||||
function JNI_OnLoad_Real(vm: pointer; reserved: pointer): longint;{$ifdef windows} stdcall {$else} cdecl {$endif}; external name 'FPC_JNI_ON_LOAD';
|
||||
procedure PascalMain; external name 'PASCALMAIN';
|
||||
|
||||
// This proxy function is called when JVM calls the JNI_OnLoad() exported function
|
||||
function JNI_OnLoad_Proxy(vm: pointer; reserved: pointer): longint;{$ifdef windows} stdcall {$else} cdecl {$endif}; [public, alias:'FPC_JNI_ON_LOAD_PROXY'];
|
||||
begin
|
||||
IsJniLibrary:=True;
|
||||
// Call library initialization
|
||||
PascalMain;
|
||||
// Call user's JNI_OnLoad().
|
||||
Result:=JNI_OnLoad_Real(vm, reserved);
|
||||
end;
|
||||
|
||||
// This procedure is called instead of library initialization when JNI_OnLoad is exported
|
||||
procedure JniLibMain; [public, alias:'FPC_JNI_LIB_MAIN_ANDROID'];
|
||||
begin
|
||||
// Must be empty.
|
||||
end;
|
||||
|
||||
// ************* System init
|
||||
|
||||
procedure InitAndroid;
|
||||
var
|
||||
i: integer;
|
||||
s: string;
|
||||
begin
|
||||
IsJniLibrary:=IsLibrary and (Pos('/system/', ParamStr(0)) = 1);
|
||||
if IsJniLibrary then
|
||||
begin
|
||||
// The library is loaded by a Java app. The proper tag will be set by SysUtils.
|
||||
|
Loading…
Reference in New Issue
Block a user