mirror of
https://gitlab.com/freepascal.org/fpc/source.git
synced 2025-08-20 13:09:15 +02:00
* android:
+ API to write to the Android system log. + API to redirect standard output and error to the Android system log. The redirection is performed automatically for shared libraries loaded by Java applications. git-svn-id: trunk@34352 -
This commit is contained in:
parent
3822515bd9
commit
419c6ce61e
@ -83,3 +83,147 @@ begin
|
|||||||
end;
|
end;
|
||||||
Result:=_ApiLevel;
|
Result:=_ApiLevel;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
// ************* Android log
|
||||||
|
|
||||||
|
var
|
||||||
|
DefaultLogTag: string[20];
|
||||||
|
|
||||||
|
function __android_log_write(prio: longint; tag, text: pchar): longint; cdecl; external 'log' name '__android_log_write';
|
||||||
|
|
||||||
|
procedure SysLogWrite(Priority: longint; Tag, Msg: PAnsiChar);
|
||||||
|
begin
|
||||||
|
__android_log_write(Priority, Tag, Msg);
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure SysLogWrite(Priority: longint; Msg: PAnsiChar);
|
||||||
|
begin
|
||||||
|
SysLogWrite(Priority, @DefaultLogTag[1], Msg);
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure SysLogWrite(Msg: PAnsiChar);
|
||||||
|
begin
|
||||||
|
SysLogWrite(DefaultSysLogPriority, @DefaultLogTag[1], Msg);
|
||||||
|
end;
|
||||||
|
|
||||||
|
// ************* STDIO redirection to Android log
|
||||||
|
|
||||||
|
const
|
||||||
|
IOBufferLength = 512;
|
||||||
|
var
|
||||||
|
IOBuf : array[0..IOBufferLength] of char;
|
||||||
|
IOLen : SizeInt;
|
||||||
|
IORedirected: boolean;
|
||||||
|
|
||||||
|
procedure OutputIOBuffer(Var F: TextRec);
|
||||||
|
var
|
||||||
|
p: longint;
|
||||||
|
begin
|
||||||
|
if (@F = @ErrOutput) or (@F = @StdErr) then
|
||||||
|
p:=ANDROID_LOG_ERROR
|
||||||
|
else
|
||||||
|
p:=DefaultSysLogPriority;
|
||||||
|
SysLogWrite(p, IOBuf);
|
||||||
|
IOLen:=0;
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure IOWrite(Var F: TextRec);
|
||||||
|
var
|
||||||
|
i, len : SizeInt;
|
||||||
|
Begin
|
||||||
|
while F.BufPos>0 do
|
||||||
|
begin
|
||||||
|
begin
|
||||||
|
if F.BufPos + IOLen > IOBufferLength then
|
||||||
|
len:=IOBufferLength - IOLen
|
||||||
|
else
|
||||||
|
len:=F.BufPos;
|
||||||
|
i:=0;
|
||||||
|
while i < len do
|
||||||
|
begin
|
||||||
|
if F.bufptr^[i] in [#10, #13] then
|
||||||
|
begin
|
||||||
|
IOBuf[IOLen]:=#0;
|
||||||
|
OutputIOBuffer(F);
|
||||||
|
Inc(i);
|
||||||
|
if (i < len) and (F.bufptr^[i - 1] = #13) and (F.bufptr^[i] = #10) then
|
||||||
|
Inc(i);
|
||||||
|
end
|
||||||
|
else
|
||||||
|
begin
|
||||||
|
IOBuf[IOLen]:=F.bufptr^[i];
|
||||||
|
Inc(IOLen);
|
||||||
|
Inc(i);
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
IOBuf[IOLen]:=#0;
|
||||||
|
end;
|
||||||
|
if IOLen = IOBufferLength then
|
||||||
|
OutputIOBuffer(F);
|
||||||
|
Dec(F.BufPos, len);
|
||||||
|
end;
|
||||||
|
End;
|
||||||
|
|
||||||
|
procedure IOClose(Var F: TextRec);
|
||||||
|
begin
|
||||||
|
if IOLen > 0 then
|
||||||
|
OutputIOBuffer(F);
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure IOOpen(Var F: TextRec);
|
||||||
|
Begin
|
||||||
|
TextRec(F).InOutFunc:=@IOWrite;
|
||||||
|
TextRec(F).FlushFunc:=@IOWrite;
|
||||||
|
TextRec(F).CloseFunc:=@IOClose;
|
||||||
|
IOLen:=0;
|
||||||
|
End;
|
||||||
|
|
||||||
|
procedure RedirectFile(Var T: Text);
|
||||||
|
begin
|
||||||
|
Assign(T,'');
|
||||||
|
TextRec(T).OpenFunc:=@IOOpen;
|
||||||
|
Rewrite(T);
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure RedirectOutputToSysLog;
|
||||||
|
begin
|
||||||
|
if IORedirected then exit;
|
||||||
|
IORedirected:=True;
|
||||||
|
RedirectFile(Output);
|
||||||
|
RedirectFile(StdOut);
|
||||||
|
RedirectFile(ErrOutput);
|
||||||
|
RedirectFile(StdErr);
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure SetDefaultSysLogTag(const Tag: string);
|
||||||
|
var
|
||||||
|
len: longint;
|
||||||
|
begin
|
||||||
|
DefaultLogTag:=Tag;
|
||||||
|
len:=Length(DefaultLogTag);
|
||||||
|
if len = High(DefaultLogTag) then
|
||||||
|
Dec(len);
|
||||||
|
DefaultLogTag[len + 1]:=#0;
|
||||||
|
end;
|
||||||
|
|
||||||
|
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.
|
||||||
|
SetDefaultSysLogTag('FPC');
|
||||||
|
RedirectOutputToSysLog;
|
||||||
|
end
|
||||||
|
else
|
||||||
|
begin
|
||||||
|
s:=ParamStr(0);
|
||||||
|
i:=Length(s);
|
||||||
|
while (i > 0) and (s[i] <> '/') do
|
||||||
|
Dec(i);
|
||||||
|
SetDefaultSysLogTag(Copy(s, i + 1, MaxInt));
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
@ -3,7 +3,7 @@
|
|||||||
Copyright (c) 2016 by Yury Sidorov,
|
Copyright (c) 2016 by Yury Sidorov,
|
||||||
member of the Free Pascal development team.
|
member of the Free Pascal development team.
|
||||||
|
|
||||||
Android-specific part of the System unit.
|
Header of Android-specific part of the System unit.
|
||||||
|
|
||||||
See the file COPYING.FPC, included in this distribution,
|
See the file COPYING.FPC, included in this distribution,
|
||||||
for details about the copyright.
|
for details about the copyright.
|
||||||
@ -13,7 +13,36 @@
|
|||||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||||
**********************************************************************}
|
**********************************************************************}
|
||||||
|
|
||||||
// Returns an Android system property
|
const
|
||||||
|
// Android system log priority
|
||||||
|
ANDROID_LOG_VERBOSE = 2;
|
||||||
|
ANDROID_LOG_DEBUG = 3;
|
||||||
|
ANDROID_LOG_INFO = 4;
|
||||||
|
ANDROID_LOG_WARN = 5;
|
||||||
|
ANDROID_LOG_ERROR = 6;
|
||||||
|
ANDROID_LOG_FATAL = 7;
|
||||||
|
|
||||||
|
// Default priority for syslog messages.
|
||||||
|
var DefaultSysLogPriority: longint = ANDROID_LOG_DEBUG;
|
||||||
|
|
||||||
|
// Set default tag for syslog messages. Initially the tag is set to the current module name.
|
||||||
|
procedure SetDefaultSysLogTag(const Tag: string);
|
||||||
|
|
||||||
|
// Write a message to the Android system log.
|
||||||
|
procedure SysLogWrite(Priority: longint; Tag, Msg: PAnsiChar); overload;
|
||||||
|
procedure SysLogWrite(Priority: longint; Msg: PAnsiChar); overload;
|
||||||
|
procedure SysLogWrite(Msg: PAnsiChar); overload;
|
||||||
|
|
||||||
|
// Redirects standard output and error to the Android system log.
|
||||||
|
// The redirection is performed automatically for shared libraries loaded by Java applications.
|
||||||
|
procedure RedirectOutputToSysLog;
|
||||||
|
|
||||||
|
// Returns an Android system property.
|
||||||
function GetSystemProperty(Name: PAnsiChar): shortstring;
|
function GetSystemProperty(Name: PAnsiChar): shortstring;
|
||||||
// Returns an Android API level of the current system
|
|
||||||
|
// Returns an Android API level of the host system.
|
||||||
function SystemApiLevel: shortint;
|
function SystemApiLevel: shortint;
|
||||||
|
|
||||||
|
// True when the current program is a shared library loaded by a Java application.
|
||||||
|
var IsJniLibrary: boolean;
|
||||||
|
|
||||||
|
@ -378,6 +378,9 @@ begin
|
|||||||
InitSystemThreads;
|
InitSystemThreads;
|
||||||
{ dynamic libraries }
|
{ dynamic libraries }
|
||||||
InitSystemDynLibs;
|
InitSystemDynLibs;
|
||||||
|
{$ifdef android}
|
||||||
|
InitAndroid;
|
||||||
|
{$endif android}
|
||||||
{ restore original signal handlers in case this is a library }
|
{ restore original signal handlers in case this is a library }
|
||||||
if IsLibrary then
|
if IsLibrary then
|
||||||
RestoreOldSignalHandlers;
|
RestoreOldSignalHandlers;
|
||||||
|
@ -80,6 +80,9 @@ procedure UnhookSignal(RtlSigNum: Integer; OnlyIfHooked: Boolean = True);
|
|||||||
implementation
|
implementation
|
||||||
|
|
||||||
Uses
|
Uses
|
||||||
|
{$ifdef android}
|
||||||
|
dl,
|
||||||
|
{$endif android}
|
||||||
{$ifdef FPC_USE_LIBC}initc{$ELSE}Syscall{$ENDIF}, Baseunix, unixutil;
|
{$ifdef FPC_USE_LIBC}initc{$ELSE}Syscall{$ENDIF}, Baseunix, unixutil;
|
||||||
|
|
||||||
type
|
type
|
||||||
@ -1428,7 +1431,6 @@ end;
|
|||||||
|
|
||||||
var
|
var
|
||||||
_HomeDir: string;
|
_HomeDir: string;
|
||||||
IsNDKLib: boolean;
|
|
||||||
|
|
||||||
Function GetHomeDir : String;
|
Function GetHomeDir : String;
|
||||||
var
|
var
|
||||||
@ -1438,7 +1440,7 @@ begin
|
|||||||
Result:=_HomeDir;
|
Result:=_HomeDir;
|
||||||
if Result <> '' then
|
if Result <> '' then
|
||||||
exit;
|
exit;
|
||||||
if IsLibrary then
|
if IsJniLibrary then
|
||||||
begin
|
begin
|
||||||
// For shared library get the package name of a host Java application
|
// For shared library get the package name of a host Java application
|
||||||
h:=FileOpen('/proc/self/cmdline', fmOpenRead or fmShareDenyNone);
|
h:=FileOpen('/proc/self/cmdline', fmOpenRead or fmShareDenyNone);
|
||||||
@ -1449,8 +1451,8 @@ begin
|
|||||||
SetLength(Result, strlen(PChar(Result)));
|
SetLength(Result, strlen(PChar(Result)));
|
||||||
FileClose(h);
|
FileClose(h);
|
||||||
Result:='/data/data/' + Result;
|
Result:='/data/data/' + Result;
|
||||||
IsNDKLib:=DirectoryExists(Result);
|
IsJniLibrary:=DirectoryExists(Result);
|
||||||
if IsNDKLib then
|
if IsJniLibrary then
|
||||||
Result:=Result + '/files/'
|
Result:=Result + '/files/'
|
||||||
else
|
else
|
||||||
Result:=''; // No package
|
Result:=''; // No package
|
||||||
@ -1497,7 +1499,7 @@ begin
|
|||||||
else
|
else
|
||||||
Result:=IncludeTrailingPathDelimiter(XdgConfigHome);
|
Result:=IncludeTrailingPathDelimiter(XdgConfigHome);
|
||||||
{$ifdef android}
|
{$ifdef android}
|
||||||
if IsNDKLib then
|
if IsJniLibrary then
|
||||||
exit;
|
exit;
|
||||||
{$endif android}
|
{$endif android}
|
||||||
if VendorName<>'' then
|
if VendorName<>'' then
|
||||||
@ -1513,7 +1515,7 @@ begin
|
|||||||
else
|
else
|
||||||
Result:=IncludeTrailingPathDelimiter(XdgConfigHome);
|
Result:=IncludeTrailingPathDelimiter(XdgConfigHome);
|
||||||
{$ifdef android}
|
{$ifdef android}
|
||||||
if IsNDKLib then
|
if IsJniLibrary then
|
||||||
begin
|
begin
|
||||||
Result:=Result+'config'+ConfigExtension;
|
Result:=Result+'config'+ConfigExtension;
|
||||||
exit;
|
exit;
|
||||||
@ -1596,6 +1598,26 @@ begin
|
|||||||
Result := -Tzseconds div 60;
|
Result := -Tzseconds div 60;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
{$ifdef android}
|
||||||
|
|
||||||
|
procedure InitAndroid;
|
||||||
|
var
|
||||||
|
dlinfo: dl_info;
|
||||||
|
s: string;
|
||||||
|
begin
|
||||||
|
if IsJniLibrary then
|
||||||
|
begin
|
||||||
|
FillChar(dlinfo, sizeof(dlinfo), 0);
|
||||||
|
dladdr(@InitAndroid, @dlinfo);
|
||||||
|
s:=dlinfo.dli_fname;
|
||||||
|
if s <> '' then
|
||||||
|
SetDefaultSysLogTag(ExtractFileName(s));
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
|
{$endif android}
|
||||||
|
|
||||||
|
|
||||||
{****************************************************************************
|
{****************************************************************************
|
||||||
Initialization code
|
Initialization code
|
||||||
****************************************************************************}
|
****************************************************************************}
|
||||||
@ -1605,7 +1627,10 @@ Initialization
|
|||||||
InitInternational; { Initialize internationalization settings }
|
InitInternational; { Initialize internationalization settings }
|
||||||
SysConfigDir:='/etc'; { Initialize system config dir }
|
SysConfigDir:='/etc'; { Initialize system config dir }
|
||||||
OnBeep:=@SysBeep;
|
OnBeep:=@SysBeep;
|
||||||
|
{$ifdef android}
|
||||||
|
InitAndroid;
|
||||||
|
{$endif android}
|
||||||
|
|
||||||
Finalization
|
Finalization
|
||||||
FreeDriveStr;
|
FreeDriveStr;
|
||||||
DoneExceptions;
|
DoneExceptions;
|
||||||
|
Loading…
Reference in New Issue
Block a user