mirror of
https://gitlab.com/freepascal.org/fpc/source.git
synced 2025-08-14 10:09:20 +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;
|
procedure generatelib;override;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
{ texportlibandroid }
|
||||||
|
|
||||||
texportlibandroid=class(texportlibunix)
|
texportlibandroid=class(texportlibunix)
|
||||||
|
public
|
||||||
procedure setfininame(list: TAsmList; const s: string); override;
|
procedure setfininame(list: TAsmList; const s: string); override;
|
||||||
|
procedure exportprocedure(hp: texported_item); override;
|
||||||
|
procedure generatelib; override;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
{ tlinkerandroid }
|
{ tlinkerandroid }
|
||||||
@ -46,6 +51,7 @@ interface
|
|||||||
private
|
private
|
||||||
prtobj : string[80];
|
prtobj : string[80];
|
||||||
reorder : boolean;
|
reorder : boolean;
|
||||||
|
FJNIOnLoadDef: tprocdef;
|
||||||
Function WriteResponseFile(isdll:boolean) : Boolean;
|
Function WriteResponseFile(isdll:boolean) : Boolean;
|
||||||
function DoLink(IsSharedLib: boolean): boolean;
|
function DoLink(IsSharedLib: boolean): boolean;
|
||||||
public
|
public
|
||||||
@ -66,12 +72,15 @@ implementation
|
|||||||
verbose,systems,globtype,globals,
|
verbose,systems,globtype,globals,
|
||||||
symconst,script,
|
symconst,script,
|
||||||
fmodule,
|
fmodule,
|
||||||
aasmbase,aasmtai,aasmcpu,cpubase,
|
aasmbase,aasmtai,aasmcpu,cpubase,hlcgcpu,hlcgobj,
|
||||||
cgbase,cgobj,cgutils,ogbase,ncgutil,
|
cgbase,cgobj,cgutils,ogbase,ncgutil,
|
||||||
comprsrc,
|
comprsrc,
|
||||||
rescmn, i_android
|
rescmn, i_android
|
||||||
;
|
;
|
||||||
|
|
||||||
|
const
|
||||||
|
SJNI_OnLoad = 'JNI_OnLoad';
|
||||||
|
|
||||||
{*****************************************************************************
|
{*****************************************************************************
|
||||||
TIMPORTLIBANDROID
|
TIMPORTLIBANDROID
|
||||||
*****************************************************************************}
|
*****************************************************************************}
|
||||||
@ -103,6 +112,44 @@ implementation
|
|||||||
inherited setfininame(list,s);
|
inherited setfininame(list,s);
|
||||||
end;
|
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
|
TLINKERANDROID
|
||||||
*****************************************************************************}
|
*****************************************************************************}
|
||||||
@ -304,6 +351,20 @@ begin
|
|||||||
add('}');
|
add('}');
|
||||||
add('INSERT BEFORE .data1');
|
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 }
|
{ Write and Close response }
|
||||||
writetodisk;
|
writetodisk;
|
||||||
Free;
|
Free;
|
||||||
|
@ -47,7 +47,7 @@ FPC_SHARED_LIB_START:
|
|||||||
str r0,[ip]
|
str r0,[ip]
|
||||||
|
|
||||||
/* Call main */
|
/* Call main */
|
||||||
blx PASCALMAIN
|
blx FPC_LIB_MAIN_ANDROID
|
||||||
/* Call library init */
|
/* Call library init */
|
||||||
blx FPC_LIB_INIT_ANDROID
|
blx FPC_LIB_INIT_ANDROID
|
||||||
|
|
||||||
|
@ -51,7 +51,7 @@ env_ok:
|
|||||||
popl %ebx
|
popl %ebx
|
||||||
|
|
||||||
/* Call main */
|
/* Call main */
|
||||||
call PASCALMAIN@PLT
|
call FPC_LIB_MAIN_ANDROID@PLT
|
||||||
/* Call library init */
|
/* Call library init */
|
||||||
call FPC_LIB_INIT_ANDROID@PLT
|
call FPC_LIB_INIT_ANDROID@PLT
|
||||||
|
|
||||||
|
@ -44,7 +44,7 @@ GotEnv:
|
|||||||
sw $t0, ($t1)
|
sw $t0, ($t1)
|
||||||
|
|
||||||
/* Call main */
|
/* Call main */
|
||||||
jal PASCALMAIN
|
jal FPC_LIB_MAIN_ANDROID
|
||||||
nop
|
nop
|
||||||
/* Call library init */
|
/* Call library init */
|
||||||
jal FPC_LIB_INIT_ANDROID
|
jal FPC_LIB_INIT_ANDROID
|
||||||
|
@ -49,7 +49,7 @@ begin
|
|||||||
{ Starting from Android 4.4 stdio handles are closed by libc prior to calling
|
{ 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
|
finalization routines of shared libraries. This causes a error while trying to
|
||||||
writeln during library finalization and finally a crash because the error can
|
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
|
It is needed to save stdout and stderr handles by duplicating them and restore
|
||||||
them before library finalization.
|
them before library finalization.
|
||||||
}
|
}
|
||||||
@ -206,12 +206,34 @@ begin
|
|||||||
DefaultLogTag[len + 1]:=#0;
|
DefaultLogTag[len + 1]:=#0;
|
||||||
end;
|
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;
|
procedure InitAndroid;
|
||||||
var
|
var
|
||||||
i: integer;
|
i: integer;
|
||||||
s: string;
|
s: string;
|
||||||
begin
|
begin
|
||||||
IsJniLibrary:=IsLibrary and (Pos('/system/', ParamStr(0)) = 1);
|
|
||||||
if IsJniLibrary then
|
if IsJniLibrary then
|
||||||
begin
|
begin
|
||||||
// The library is loaded by a Java app. The proper tag will be set by SysUtils.
|
// The library is loaded by a Java app. The proper tag will be set by SysUtils.
|
||||||
|
Loading…
Reference in New Issue
Block a user