sysandroid.inc 6.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251
  1. {
  2. This file is part of the Free Pascal run time library.
  3. Copyright (c) 2015 by Yury Sidorov,
  4. member of the Free Pascal development team.
  5. Android-specific part of the System unit.
  6. See the file COPYING.FPC, included in this distribution,
  7. for details about the copyright.
  8. This program is distributed in the hope that it will be useful,
  9. but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  11. **********************************************************************}
  12. procedure atexit(p: pointer); cdecl; external;
  13. var
  14. _SaveStdOut: THandle;
  15. _SaveStdErr: THandle;
  16. procedure SysAndroidLibExit; cdecl;
  17. var
  18. ioclosed: boolean;
  19. begin
  20. // Check if stdio is closed now
  21. ioclosed:=do_syscall(syscall_nr_fcntl, TSysParam(1), 1 {F_GETFD}) = -1;
  22. // If stdio is closed, restore stdout and stderr
  23. if ioclosed then
  24. begin
  25. FpDup2(_SaveStdOut, 1);
  26. FpDup2(_SaveStdErr, 2);
  27. end;
  28. // Close saved handles
  29. FpClose(_SaveStdOut);
  30. FpClose(_SaveStdErr);
  31. // Finalize the library
  32. lib_exit;
  33. // Close stdout and stderr if stdio has been closed
  34. if ioclosed then
  35. begin
  36. FpClose(1);
  37. FpClose(2);
  38. end;
  39. end;
  40. procedure SysInitAndroidLib; [public, alias:'FPC_LIB_INIT_ANDROID'];
  41. begin
  42. { Starting from Android 4.4 stdio handles are closed by libc prior to calling
  43. finalization routines of shared libraries. This causes a error while trying to
  44. writeln during library finalization and finally a crash because the error can
  45. not be printed too.
  46. It is needed to save stdout and stderr handles by duplicating them and restore
  47. them before library finalization.
  48. }
  49. _SaveStdOut:=FpDup(1);
  50. _SaveStdErr:=FpDup(2);
  51. // Register the finalization routine
  52. atexit(@SysAndroidLibExit);
  53. end;
  54. function __system_property_get(name:Pchar; value:Pchar):longint;cdecl;external 'c' name '__system_property_get';
  55. function GetSystemProperty(Name: PAnsiChar): shortstring;
  56. begin
  57. SetLength(Result, __system_property_get(Name, @Result[1]));
  58. end;
  59. var
  60. _ApiLevel: shortint = -1;
  61. function SystemApiLevel: shortint;
  62. var
  63. s: string;
  64. c: integer;
  65. begin
  66. if _ApiLevel < 0 then
  67. begin
  68. s:=GetSystemProperty('ro.build.version.sdk');
  69. Val(s, _ApiLevel, c);
  70. if c <> 0 then
  71. _ApiLevel:=0;
  72. end;
  73. Result:=_ApiLevel;
  74. end;
  75. // ************* Android log
  76. var
  77. DefaultLogTag: string[20];
  78. function __android_log_write(prio: longint; tag, text: pchar): longint; cdecl; external 'log' name '__android_log_write';
  79. procedure SysLogWrite(Priority: longint; Tag, Msg: PAnsiChar);
  80. begin
  81. __android_log_write(Priority, Tag, Msg);
  82. end;
  83. procedure SysLogWrite(Priority: longint; Msg: PAnsiChar);
  84. begin
  85. SysLogWrite(Priority, @DefaultLogTag[1], Msg);
  86. end;
  87. procedure SysLogWrite(Msg: PAnsiChar);
  88. begin
  89. SysLogWrite(DefaultSysLogPriority, @DefaultLogTag[1], Msg);
  90. end;
  91. // ************* STDIO redirection to Android log
  92. const
  93. IOBufferLength = 512;
  94. var
  95. IOBuf : array[0..IOBufferLength] of char;
  96. IOLen : SizeInt;
  97. IORedirected: boolean;
  98. procedure OutputIOBuffer(Var F: TextRec);
  99. var
  100. p: longint;
  101. begin
  102. if (@F = @ErrOutput) or (@F = @StdErr) then
  103. p:=ANDROID_LOG_ERROR
  104. else
  105. p:=DefaultSysLogPriority;
  106. SysLogWrite(p, IOBuf);
  107. IOLen:=0;
  108. end;
  109. procedure IOWrite(Var F: TextRec);
  110. var
  111. i, len : SizeInt;
  112. Begin
  113. while F.BufPos>0 do
  114. begin
  115. begin
  116. if F.BufPos + IOLen > IOBufferLength then
  117. len:=IOBufferLength - IOLen
  118. else
  119. len:=F.BufPos;
  120. i:=0;
  121. while i < len do
  122. begin
  123. if F.bufptr^[i] in [#10, #13] then
  124. begin
  125. IOBuf[IOLen]:=#0;
  126. OutputIOBuffer(F);
  127. Inc(i);
  128. if (i < len) and (F.bufptr^[i - 1] = #13) and (F.bufptr^[i] = #10) then
  129. Inc(i);
  130. end
  131. else
  132. begin
  133. IOBuf[IOLen]:=F.bufptr^[i];
  134. Inc(IOLen);
  135. Inc(i);
  136. end;
  137. end;
  138. IOBuf[IOLen]:=#0;
  139. end;
  140. if IOLen = IOBufferLength then
  141. OutputIOBuffer(F);
  142. Dec(F.BufPos, len);
  143. end;
  144. End;
  145. procedure IOClose(Var F: TextRec);
  146. begin
  147. if IOLen > 0 then
  148. OutputIOBuffer(F);
  149. end;
  150. procedure IOOpen(Var F: TextRec);
  151. Begin
  152. TextRec(F).InOutFunc:=@IOWrite;
  153. TextRec(F).FlushFunc:=@IOWrite;
  154. TextRec(F).CloseFunc:=@IOClose;
  155. IOLen:=0;
  156. End;
  157. procedure RedirectFile(Var T: Text);
  158. begin
  159. Assign(T,'');
  160. TextRec(T).OpenFunc:=@IOOpen;
  161. Rewrite(T);
  162. end;
  163. procedure RedirectOutputToSysLog;
  164. begin
  165. if IORedirected then exit;
  166. IORedirected:=True;
  167. RedirectFile(Output);
  168. RedirectFile(StdOut);
  169. RedirectFile(ErrOutput);
  170. RedirectFile(StdErr);
  171. end;
  172. procedure SetDefaultSysLogTag(const Tag: string);
  173. var
  174. len: longint;
  175. begin
  176. DefaultLogTag:=Tag;
  177. len:=Length(DefaultLogTag);
  178. if len = High(DefaultLogTag) then
  179. Dec(len);
  180. DefaultLogTag[len + 1]:=#0;
  181. end;
  182. // ************* JNI init
  183. function JNI_OnLoad_Real(vm: pointer; reserved: pointer): longint;{$ifdef windows} stdcall {$else} cdecl {$endif}; external name 'FPC_JNI_ON_LOAD';
  184. procedure PascalMain; external name 'PASCALMAIN';
  185. // This proxy function is called when JVM calls the JNI_OnLoad() exported function
  186. function JNI_OnLoad_Proxy(vm: pointer; reserved: pointer): longint;{$ifdef windows} stdcall {$else} cdecl {$endif}; [public, alias:'FPC_JNI_ON_LOAD_PROXY'];
  187. begin
  188. IsJniLibrary:=True;
  189. // Call library initialization
  190. PascalMain;
  191. // Call user's JNI_OnLoad().
  192. Result:=JNI_OnLoad_Real(vm, reserved);
  193. end;
  194. // This procedure is called instead of library initialization when JNI_OnLoad is exported
  195. procedure JniLibMain; [public, alias:'FPC_JNI_LIB_MAIN_ANDROID'];
  196. begin
  197. // Must be empty.
  198. end;
  199. // ************* System init
  200. procedure InitAndroid;
  201. var
  202. i: integer;
  203. s: string;
  204. begin
  205. if IsJniLibrary then
  206. begin
  207. // The library is loaded by a Java app. The proper tag will be set by SysUtils.
  208. SetDefaultSysLogTag('FPC');
  209. RedirectOutputToSysLog;
  210. end
  211. else
  212. begin
  213. s:=ParamStr(0);
  214. i:=Length(s);
  215. while (i > 0) and (s[i] <> '/') do
  216. Dec(i);
  217. SetDefaultSysLogTag(Copy(s, i + 1, MaxInt));
  218. end;
  219. end;