* 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:
yury 2016-08-19 20:21:52 +00:00
parent 3822515bd9
commit 419c6ce61e
4 changed files with 211 additions and 10 deletions

View File

@ -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;

View File

@ -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;

View File

@ -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;

View File

@ -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;