sysandroid.inc 8.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333
  1. {
  2. This file is part of the Free Pascal run time library.
  3. Copyright (c) 2015-2018 by Yuriy Sydorov,
  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. var
  13. __stkptr : Pointer; public name '__stkptr';
  14. operatingsystem_parameter_envp : Pointer; public name 'operatingsystem_parameter_envp';
  15. operatingsystem_parameter_argc : LongInt; public name 'operatingsystem_parameter_argc';
  16. operatingsystem_parameter_argv : Pointer; public name 'operatingsystem_parameter_argv';
  17. _environ: pointer external name 'environ';
  18. procedure CommonMainAndroid;
  19. const
  20. EmptyEnv: array[0..2] of PAnsiChar = (nil, nil, nil);
  21. EmptyCmdLine: array[0..0] of PAnsiChar = ( '' );
  22. var
  23. i: cardinal;
  24. p: PPAnsiChar;
  25. begin
  26. // Get the current stack pointer, adjust and save it
  27. __stkptr:=pointer(ptruint(Sptr) or $FFFF);
  28. // Get the environment from the environ variable of libc
  29. p:=_environ;
  30. if p = nil then
  31. operatingsystem_parameter_envp:=@EmptyEnv
  32. else
  33. begin
  34. operatingsystem_parameter_envp:=p;
  35. // Finding argc and argv. They are placed before envp
  36. Dec(p);
  37. if p^ = nil then
  38. begin
  39. i:=0;
  40. while i < 200 do
  41. begin
  42. Dec(p);
  43. if ptruint(p^) = i then
  44. begin
  45. // argc found
  46. operatingsystem_parameter_argc:=i;
  47. operatingsystem_parameter_argv:=p + 1;
  48. break;
  49. end;
  50. Inc(i);
  51. end;
  52. end;
  53. end;
  54. if operatingsystem_parameter_argc = 0 then
  55. begin
  56. // argc and argv are not available
  57. operatingsystem_parameter_argc:=1;
  58. operatingsystem_parameter_argv:=@EmptyCmdLine;
  59. end;
  60. end;
  61. // ************* Program startup code
  62. procedure ProgMainAndroid; cdecl; [public, alias:'FPC_PROG_START_ANDROID'];
  63. begin
  64. CommonMainAndroid;
  65. end;
  66. // ************* Shared library startup code
  67. procedure LibMainAndroid; external name 'FPC_LIB_MAIN_ANDROID';
  68. procedure atexit(p: pointer); cdecl; external;
  69. var
  70. _SaveStdOut: THandle;
  71. _SaveStdErr: THandle;
  72. procedure SysAndroidLibExit; cdecl;
  73. var
  74. ioclosed: boolean;
  75. begin
  76. // Check if stdio is closed now
  77. ioclosed:=do_syscall(syscall_nr_fcntl, TSysParam(1), 1 {F_GETFD}) = -1;
  78. // If stdio is closed, restore stdout and stderr
  79. if ioclosed then
  80. begin
  81. FpDup2(_SaveStdOut, 1);
  82. FpDup2(_SaveStdErr, 2);
  83. end;
  84. // Close saved handles
  85. FpClose(_SaveStdOut);
  86. FpClose(_SaveStdErr);
  87. // Finalize the library
  88. lib_exit;
  89. // Close stdout and stderr if stdio has been closed
  90. if ioclosed then
  91. begin
  92. FpClose(1);
  93. FpClose(2);
  94. end;
  95. end;
  96. // This procedure is called first when a shared library is loaded
  97. procedure AndroidLibStart; cdecl; [public, alias:'FPC_LIB_START_ANDROID'];
  98. begin
  99. CommonMainAndroid;
  100. // Call main code FPC_LIB_MAIN_ANDROID of the library.
  101. // It points either to a standard PASCALMAIN or FPC_JNI_LIB_MAIN_ANDROID if JNI_OnLoad is exported by the library
  102. // The linker makes all the magic.
  103. LibMainAndroid;
  104. { Starting from Android 4.4 stdio handles are closed by libc prior to calling
  105. finalization routines of shared libraries. This causes a error while trying to
  106. writeln during library finalization and finally a crash because the error can
  107. not be printed too.
  108. It is needed to save stdout and stderr handles by duplicating them and restore
  109. them before library finalization.
  110. }
  111. _SaveStdOut:=FpDup(1);
  112. _SaveStdErr:=FpDup(2);
  113. // Register the finalization routine
  114. atexit(@SysAndroidLibExit);
  115. end;
  116. // ************* JNI init
  117. function JNI_OnLoad_Real(vm: pointer; reserved: pointer): longint;{$ifdef windows} stdcall {$else} cdecl {$endif}; external name 'FPC_JNI_ON_LOAD';
  118. procedure PascalMain; external name 'PASCALMAIN';
  119. // This proxy function is called when JVM calls the JNI_OnLoad() exported function
  120. function JNI_OnLoad_Proxy(vm: pointer; reserved: pointer): longint;{$ifdef windows} stdcall {$else} cdecl {$endif}; [public, alias:'FPC_JNI_ON_LOAD_PROXY'];
  121. begin
  122. IsJniLibrary:=True;
  123. // Call library initialization
  124. PascalMain;
  125. // Call user's JNI_OnLoad().
  126. Result:=JNI_OnLoad_Real(vm, reserved);
  127. end;
  128. // This procedure is called instead of library initialization when JNI_OnLoad is exported
  129. procedure JniLibMain; [public, alias:'FPC_JNI_LIB_MAIN_ANDROID'];
  130. begin
  131. // Must be empty.
  132. end;
  133. // ************* haltproc
  134. procedure _exit(e:longint); cdecl; external name 'exit';
  135. procedure _haltproc(e:longint);cdecl; [public, alias: {$if defined(CPUARM) and defined(FPC_ABI_EABI)} '_haltproc_eabi' {$else} '_haltproc' {$endif}];
  136. begin
  137. _exit(e);
  138. end;
  139. // ************* Misc functions
  140. function __system_property_get(name:Pchar; value:Pchar):longint;cdecl;external 'c' name '__system_property_get';
  141. function GetSystemProperty(Name: PAnsiChar): shortstring;
  142. begin
  143. SetLength(Result, __system_property_get(Name, @Result[1]));
  144. end;
  145. var
  146. _ApiLevel: shortint = -1;
  147. function SystemApiLevel: shortint;
  148. var
  149. s: string;
  150. c: integer;
  151. begin
  152. if _ApiLevel < 0 then
  153. begin
  154. s:=GetSystemProperty('ro.build.version.sdk');
  155. Val(s, _ApiLevel, c);
  156. if c <> 0 then
  157. _ApiLevel:=0;
  158. end;
  159. Result:=_ApiLevel;
  160. end;
  161. // ************* Android log
  162. var
  163. DefaultLogTag: string[20];
  164. function __android_log_write(prio: longint; tag, text: pchar): longint; cdecl; external 'log' name '__android_log_write';
  165. procedure SysLogWrite(Priority: longint; Tag, Msg: PAnsiChar);
  166. begin
  167. __android_log_write(Priority, Tag, Msg);
  168. end;
  169. procedure SysLogWrite(Priority: longint; Msg: PAnsiChar);
  170. begin
  171. SysLogWrite(Priority, @DefaultLogTag[1], Msg);
  172. end;
  173. procedure SysLogWrite(Msg: PAnsiChar);
  174. begin
  175. SysLogWrite(DefaultSysLogPriority, @DefaultLogTag[1], Msg);
  176. end;
  177. // ************* STDIO redirection to Android log
  178. const
  179. IOBufferLength = 512;
  180. var
  181. IOBuf : array[0..IOBufferLength] of char;
  182. IOLen : SizeInt;
  183. IORedirected: boolean;
  184. procedure OutputIOBuffer(Var F: TextRec);
  185. var
  186. p: longint;
  187. begin
  188. if (@F = @ErrOutput) or (@F = @StdErr) then
  189. p:=ANDROID_LOG_ERROR
  190. else
  191. p:=DefaultSysLogPriority;
  192. SysLogWrite(p, IOBuf);
  193. IOLen:=0;
  194. end;
  195. procedure IOWrite(Var F: TextRec);
  196. var
  197. i, len : SizeInt;
  198. Begin
  199. while F.BufPos>0 do
  200. begin
  201. begin
  202. if F.BufPos + IOLen > IOBufferLength then
  203. len:=IOBufferLength - IOLen
  204. else
  205. len:=F.BufPos;
  206. i:=0;
  207. while i < len do
  208. begin
  209. if F.bufptr^[i] in [#10, #13] then
  210. begin
  211. IOBuf[IOLen]:=#0;
  212. OutputIOBuffer(F);
  213. Inc(i);
  214. if (i < len) and (F.bufptr^[i - 1] = #13) and (F.bufptr^[i] = #10) then
  215. Inc(i);
  216. end
  217. else
  218. begin
  219. IOBuf[IOLen]:=F.bufptr^[i];
  220. Inc(IOLen);
  221. Inc(i);
  222. end;
  223. end;
  224. IOBuf[IOLen]:=#0;
  225. end;
  226. if IOLen = IOBufferLength then
  227. OutputIOBuffer(F);
  228. Dec(F.BufPos, len);
  229. end;
  230. End;
  231. procedure IOClose(Var F: TextRec);
  232. begin
  233. if IOLen > 0 then
  234. OutputIOBuffer(F);
  235. end;
  236. procedure IOOpen(Var F: TextRec);
  237. Begin
  238. TextRec(F).InOutFunc:=@IOWrite;
  239. TextRec(F).FlushFunc:=@IOWrite;
  240. TextRec(F).CloseFunc:=@IOClose;
  241. IOLen:=0;
  242. End;
  243. procedure RedirectFile(Var T: Text);
  244. begin
  245. Assign(T,'');
  246. TextRec(T).OpenFunc:=@IOOpen;
  247. Rewrite(T);
  248. end;
  249. procedure RedirectOutputToSysLog;
  250. begin
  251. if IORedirected then exit;
  252. IORedirected:=True;
  253. RedirectFile(Output);
  254. RedirectFile(StdOut);
  255. RedirectFile(ErrOutput);
  256. RedirectFile(StdErr);
  257. end;
  258. procedure SetDefaultSysLogTag(const Tag: string);
  259. var
  260. len: longint;
  261. begin
  262. DefaultLogTag:=Tag;
  263. len:=Length(DefaultLogTag);
  264. if len = High(DefaultLogTag) then
  265. Dec(len);
  266. DefaultLogTag[len + 1]:=#0;
  267. end;
  268. // ************* System init
  269. procedure InitAndroid;
  270. var
  271. i: integer;
  272. s: string;
  273. begin
  274. if IsJniLibrary then
  275. begin
  276. // The library is loaded by a Java app. The proper tag will be set by SysUtils.
  277. SetDefaultSysLogTag('FPC');
  278. RedirectOutputToSysLog;
  279. end
  280. else
  281. begin
  282. s:=ParamStr(0);
  283. i:=Length(s);
  284. while (i > 0) and (s[i] <> '/') do
  285. Dec(i);
  286. SetDefaultSysLogTag(Copy(s, i + 1, MaxInt));
  287. end;
  288. end;