Ver código fonte

* 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 -

yury 9 anos atrás
pai
commit
419c6ce61e
4 arquivos alterados com 211 adições e 10 exclusões
  1. 144 0
      rtl/android/sysandroid.inc
  2. 32 3
      rtl/android/sysandroidh.inc
  3. 3 0
      rtl/linux/system.pp
  4. 32 7
      rtl/unix/sysutils.pp

+ 144 - 0
rtl/android/sysandroid.inc

@@ -83,3 +83,147 @@ begin
     end;
   Result:=_ApiLevel;
 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;

+ 32 - 3
rtl/android/sysandroidh.inc

@@ -3,7 +3,7 @@
     Copyright (c) 2016 by Yury Sidorov,
     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,
     for details about the copyright.
@@ -13,7 +13,36 @@
     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;
-// Returns an Android API level of the current system
+
+// Returns an Android API level of the host system.
 function SystemApiLevel: shortint;
+
+// True when the current program is a shared library loaded by a Java application.
+var IsJniLibrary: boolean;
+

+ 3 - 0
rtl/linux/system.pp

@@ -378,6 +378,9 @@ begin
   InitSystemThreads;
   { dynamic libraries }
   InitSystemDynLibs;
+{$ifdef android}
+  InitAndroid;
+{$endif android}
   { restore original signal handlers in case this is a library }
   if IsLibrary then
     RestoreOldSignalHandlers;

+ 32 - 7
rtl/unix/sysutils.pp

@@ -80,6 +80,9 @@ procedure UnhookSignal(RtlSigNum: Integer; OnlyIfHooked: Boolean = True);
 implementation
 
 Uses
+{$ifdef android}
+  dl,
+{$endif android}
   {$ifdef FPC_USE_LIBC}initc{$ELSE}Syscall{$ENDIF}, Baseunix, unixutil;
 
 type
@@ -1428,7 +1431,6 @@ end;
 
 var
   _HomeDir: string;
-  IsNDKLib: boolean;
 
 Function GetHomeDir : String;
 var
@@ -1438,7 +1440,7 @@ begin
   Result:=_HomeDir;
   if Result <> '' then
     exit;
-  if IsLibrary then
+  if IsJniLibrary then
     begin
       // For shared library get the package name of a host Java application
       h:=FileOpen('/proc/self/cmdline', fmOpenRead or fmShareDenyNone);
@@ -1449,8 +1451,8 @@ begin
           SetLength(Result, strlen(PChar(Result)));
           FileClose(h);
           Result:='/data/data/' + Result;
-          IsNDKLib:=DirectoryExists(Result);
-          if IsNDKLib then
+          IsJniLibrary:=DirectoryExists(Result);
+          if IsJniLibrary then
             Result:=Result + '/files/'
           else
             Result:='';  // No package
@@ -1497,7 +1499,7 @@ begin
   else
     Result:=IncludeTrailingPathDelimiter(XdgConfigHome);
 {$ifdef android}
-  if IsNDKLib then
+  if IsJniLibrary then
     exit;
 {$endif android}
   if VendorName<>'' then
@@ -1513,7 +1515,7 @@ begin
   else
     Result:=IncludeTrailingPathDelimiter(XdgConfigHome);
 {$ifdef android}
-  if IsNDKLib then
+  if IsJniLibrary then
     begin
       Result:=Result+'config'+ConfigExtension;
       exit;
@@ -1596,6 +1598,26 @@ begin
  Result := -Tzseconds div 60; 
 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
 ****************************************************************************}
@@ -1605,7 +1627,10 @@ Initialization
   InitInternational;    { Initialize internationalization settings }
   SysConfigDir:='/etc'; { Initialize system config dir }
   OnBeep:=@SysBeep;
-  
+{$ifdef android}
+  InitAndroid;
+{$endif android}
+
 Finalization
   FreeDriveStr;
   DoneExceptions;