sysandroid.inc 8.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335
  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. var
  182. IOBuf : array[0..IOBufferLength] of char;
  183. IOLen : SizeInt;
  184. IORedirected: boolean;
  185. procedure OutputIOBuffer(Var F: TextRec);
  186. var
  187. p: longint;
  188. begin
  189. if (@F = @ErrOutput) or (@F = @StdErr) then
  190. p:=ANDROID_LOG_ERROR
  191. else
  192. p:=DefaultSysLogPriority;
  193. SysLogWrite(p, IOBuf);
  194. IOLen:=0;
  195. end;
  196. procedure IOWrite(Var F: TextRec);
  197. var
  198. i, len : SizeInt;
  199. Begin
  200. while F.BufPos>0 do
  201. begin
  202. begin
  203. if F.BufPos + IOLen > IOBufferLength then
  204. len:=IOBufferLength - IOLen
  205. else
  206. len:=F.BufPos;
  207. i:=0;
  208. while i < len do
  209. begin
  210. if F.bufptr^[i] in [#10, #13] then
  211. begin
  212. IOBuf[IOLen]:=#0;
  213. OutputIOBuffer(F);
  214. Inc(i);
  215. if (i < len) and (F.bufptr^[i - 1] = #13) and (F.bufptr^[i] = #10) then
  216. Inc(i);
  217. end
  218. else
  219. begin
  220. IOBuf[IOLen]:=F.bufptr^[i];
  221. Inc(IOLen);
  222. Inc(i);
  223. end;
  224. end;
  225. IOBuf[IOLen]:=#0;
  226. end;
  227. if IOLen = IOBufferLength then
  228. OutputIOBuffer(F);
  229. Dec(F.BufPos, len);
  230. end;
  231. End;
  232. procedure IOClose(Var F: TextRec);
  233. begin
  234. if IOLen > 0 then
  235. OutputIOBuffer(F);
  236. end;
  237. procedure IOOpen(Var F: TextRec);
  238. Begin
  239. TextRec(F).InOutFunc:=@IOWrite;
  240. TextRec(F).FlushFunc:=@IOWrite;
  241. TextRec(F).CloseFunc:=@IOClose;
  242. IOLen:=0;
  243. End;
  244. procedure RedirectFile(Var T: Text);
  245. begin
  246. Assign(T,'');
  247. TextRec(T).OpenFunc:=@IOOpen;
  248. Rewrite(T);
  249. end;
  250. procedure RedirectOutputToSysLog;
  251. begin
  252. if IORedirected then exit;
  253. IORedirected:=True;
  254. RedirectFile(Output);
  255. RedirectFile(StdOut);
  256. RedirectFile(ErrOutput);
  257. RedirectFile(StdErr);
  258. end;
  259. procedure SetDefaultSysLogTag(const Tag: string);
  260. var
  261. len: longint;
  262. begin
  263. DefaultLogTag:=Tag;
  264. len:=Length(DefaultLogTag);
  265. if len = High(DefaultLogTag) then
  266. Dec(len);
  267. DefaultLogTag[len + 1]:=#0;
  268. end;
  269. // ************* System init
  270. procedure InitAndroid;
  271. var
  272. i: integer;
  273. s: string;
  274. begin
  275. if IsJniLibrary then
  276. begin
  277. // The library is loaded by a Java app. The proper tag will be set by SysUtils.
  278. SetDefaultSysLogTag('FPC');
  279. RedirectOutputToSysLog;
  280. end
  281. else
  282. begin
  283. s:=ParamStr(0);
  284. i:=Length(s);
  285. while (i > 0) and (s[i] <> '/') do
  286. Dec(i);
  287. SetDefaultSysLogTag(Copy(s, i + 1, MaxInt));
  288. end;
  289. end;