sysandroid.inc 8.7 KB

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