2
0

sysandroid.inc 8.8 KB

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