platform_unix.c 91 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327232823292330233123322333233423352336233723382339234023412342234323442345234623472348234923502351235223532354235523562357235823592360236123622363236423652366236723682369237023712372237323742375237623772378237923802381238223832384238523862387238823892390239123922393239423952396239723982399240024012402240324042405240624072408240924102411241224132414241524162417241824192420242124222423242424252426242724282429243024312432243324342435243624372438243924402441244224432444244524462447244824492450245124522453245424552456245724582459246024612462246324642465246624672468246924702471247224732474247524762477247824792480248124822483248424852486248724882489249024912492249324942495249624972498249925002501250225032504250525062507250825092510251125122513251425152516251725182519252025212522252325242525252625272528252925302531253225332534253525362537253825392540254125422543254425452546254725482549255025512552255325542555255625572558255925602561256225632564256525662567256825692570257125722573257425752576257725782579258025812582258325842585258625872588258925902591259225932594259525962597259825992600260126022603260426052606260726082609261026112612261326142615261626172618261926202621262226232624262526262627262826292630263126322633263426352636263726382639264026412642264326442645264626472648264926502651265226532654265526562657265826592660266126622663266426652666266726682669267026712672267326742675267626772678267926802681268226832684268526862687268826892690269126922693269426952696269726982699270027012702270327042705270627072708270927102711271227132714271527162717271827192720272127222723272427252726272727282729273027312732273327342735273627372738273927402741274227432744274527462747274827492750275127522753275427552756275727582759276027612762276327642765276627672768276927702771277227732774277527762777277827792780278127822783278427852786278727882789279027912792279327942795279627972798279928002801280228032804280528062807280828092810281128122813281428152816281728182819282028212822282328242825282628272828282928302831283228332834283528362837283828392840284128422843284428452846284728482849285028512852285328542855285628572858285928602861286228632864286528662867286828692870287128722873287428752876287728782879288028812882288328842885288628872888288928902891289228932894289528962897289828992900290129022903290429052906290729082909291029112912291329142915291629172918291929202921292229232924292529262927292829292930293129322933293429352936293729382939294029412942294329442945294629472948294929502951295229532954295529562957295829592960296129622963296429652966296729682969297029712972297329742975297629772978297929802981298229832984298529862987298829892990299129922993299429952996299729982999300030013002300330043005300630073008300930103011301230133014301530163017301830193020302130223023302430253026302730283029303030313032303330343035303630373038303930403041304230433044304530463047304830493050305130523053305430553056305730583059306030613062306330643065306630673068306930703071
  1. /* RetroArch - A frontend for libretro.
  2. * Copyright (C) 2010-2014 - Hans-Kristian Arntzen
  3. * Copyright (C) 2011-2017 - Daniel De Matteis
  4. * Copyright (C) 2012-2015 - Jason Fetters
  5. * Copyright (C) 2012-2015 - Michael Lelli
  6. * Copyright (C) 2016-2019 - Andrés Suárez
  7. *
  8. * RetroArch is free software: you can redistribute it and/or modify it under the terms
  9. * of the GNU General Public License as published by the Free Software Found-
  10. * ation, either version 3 of the License, or (at your option) any later version.
  11. *
  12. * RetroArch is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
  13. * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
  14. * PURPOSE. See the GNU General Public License for more details.
  15. * * You should have received a copy of the GNU General Public License along with RetroArch.
  16. * If not, see <http://www.gnu.org/licenses/>.
  17. */
  18. #include "retro_miscellaneous.h"
  19. #include <jni.h>
  20. #include <stdio.h>
  21. #include <stdint.h>
  22. #include <stddef.h>
  23. #include <stdlib.h>
  24. #include <string.h>
  25. #include <unistd.h>
  26. #include <fcntl.h>
  27. #include <sys/utsname.h>
  28. #include <sys/resource.h>
  29. #ifdef __linux__
  30. #include <linux/version.h>
  31. #if __STDC_VERSION__ >= 199901L && !defined(ANDROID)
  32. #include "feralgamemode/gamemode_client.h"
  33. #define FERAL_GAMEMODE
  34. #endif
  35. /* inotify API was added in 2.6.13 */
  36. #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,13)
  37. #define HAS_INOTIFY
  38. #define INOTIFY_BUF_LEN (1024 * (sizeof(struct inotify_event) + 16))
  39. #include <sys/inotify.h>
  40. #define VECTOR_LIST_TYPE int
  41. #define VECTOR_LIST_NAME int
  42. #include "../../libretro-common/lists/vector_list.c"
  43. #undef VECTOR_LIST_TYPE
  44. #undef VECTOR_LIST_NAME
  45. #endif
  46. #endif
  47. #include <signal.h>
  48. #include <pthread.h>
  49. #ifdef HAVE_CONFIG_H
  50. #include "../../config.h"
  51. #endif
  52. #ifdef ANDROID
  53. #include <sys/system_properties.h>
  54. #endif
  55. #if defined(DINGUX)
  56. #include "../../dingux/dingux_utils.h"
  57. #endif
  58. #include <boolean.h>
  59. #include <retro_dirent.h>
  60. #include <retro_inline.h>
  61. #include <compat/strl.h>
  62. #include <compat/fopen_utf8.h>
  63. #include <lists/file_list.h>
  64. #include <file/file_path.h>
  65. #include <streams/file_stream.h>
  66. #include <string/stdstring.h>
  67. #include <queues/task_queue.h>
  68. #include <retro_timers.h>
  69. #include <features/features_cpu.h>
  70. #include "../frontend.h"
  71. #include "../frontend_driver.h"
  72. #include "../../defaults.h"
  73. #include "../../msg_hash.h"
  74. #include "../../paths.h"
  75. #include "../../retroarch.h"
  76. #include "../../verbosity.h"
  77. #ifdef HAVE_MENU
  78. #include "../../menu/menu_driver.h"
  79. #include "../../menu/menu_entries.h"
  80. #else
  81. #include "../../command.h"
  82. #endif
  83. #include "platform_unix.h"
  84. #ifdef ANDROID
  85. static void frontend_unix_set_sustained_performance_mode(bool on);
  86. enum
  87. {
  88. /* Internal SDCARD writable */
  89. INTERNAL_STORAGE_WRITABLE = 1,
  90. /* Internal SDCARD not writable but the private app dir is */
  91. INTERNAL_STORAGE_APPDIR_WRITABLE,
  92. /* Internal SDCARD not writable at all */
  93. INTERNAL_STORAGE_NOT_WRITABLE
  94. };
  95. enum platform_android_flags
  96. {
  97. PLAT_ANDROID_FLAG_GAME_CONSOLE_DEVICE = (1 << 0),
  98. PLAT_ANDROID_FLAG_ANDROID_TV_DEVICE = (1 << 1),
  99. PLAT_ANDROID_FLAG_XPERIA_PLAY_DEVICE = (1 << 2)
  100. };
  101. static pthread_key_t thread_key;
  102. static char app_dir[PATH_MAX_LENGTH];
  103. unsigned storage_permissions = 0;
  104. struct android_app *g_android = NULL;
  105. static uint8_t g_platform_android_flags = 0;
  106. #else
  107. #define PROC_APM_PATH "/proc/apm"
  108. #define PROC_ACPI_BATTERY_PATH "/proc/acpi/battery"
  109. #define PROC_ACPI_SYSFS_AC_ADAPTER_PATH "/sys/class/power_supply/ACAD"
  110. #define PROC_ACPI_SYSFS_BATTERY_PATH "/sys/class/power_supply"
  111. #define PROC_ACPI_AC_ADAPTER_PATH "/proc/acpi/ac_adapter"
  112. static char unix_cpu_model_name[64] = {0};
  113. #endif
  114. /* /proc/meminfo parameters */
  115. #define PROC_MEMINFO_PATH "/proc/meminfo"
  116. #define PROC_MEMINFO_MEM_TOTAL_TAG "MemTotal:"
  117. #define PROC_MEMINFO_MEM_AVAILABLE_TAG "MemAvailable:"
  118. #define PROC_MEMINFO_MEM_FREE_TAG "MemFree:"
  119. #define PROC_MEMINFO_BUFFERS_TAG "Buffers:"
  120. #define PROC_MEMINFO_CACHED_TAG "Cached:"
  121. #define PROC_MEMINFO_SHMEM_TAG "Shmem:"
  122. #if (defined(__linux__) || defined(__unix__)) && !defined(ANDROID)
  123. static int speak_pid = 0;
  124. #endif
  125. static volatile sig_atomic_t unix_sighandler_quit;
  126. #ifndef ANDROID
  127. static enum frontend_fork unix_fork_mode = FRONTEND_FORK_NONE;
  128. #endif
  129. #ifdef HAS_INOTIFY
  130. typedef struct inotify_data
  131. {
  132. int fd;
  133. int flags;
  134. struct int_vector_list *wd_list;
  135. struct string_list *path_list;
  136. } inotify_data_t;
  137. #endif
  138. int system_property_get(const char *command,
  139. const char *args, char *value)
  140. {
  141. FILE *pipe;
  142. char buffer[BUFSIZ];
  143. char cmd[NAME_MAX_LENGTH];
  144. int length = 0;
  145. char *curpos = NULL;
  146. size_t buf_pos = strlcpy(cmd, command, sizeof(cmd));
  147. cmd[buf_pos] = ' ';
  148. cmd[buf_pos+1] = '\0';
  149. buf_pos = strlcat(cmd, args, sizeof(cmd));
  150. if (!(pipe = popen(cmd, "r")))
  151. {
  152. RARCH_ERR("Could not create pipe.\n");
  153. return 0;
  154. }
  155. curpos = value;
  156. while (!feof(pipe))
  157. {
  158. if (fgets(buffer, sizeof(buffer), pipe))
  159. {
  160. size_t curlen = strlen(buffer);
  161. memcpy(curpos, buffer, curlen);
  162. curpos += curlen;
  163. length += curlen;
  164. }
  165. }
  166. *curpos = '\0';
  167. pclose(pipe);
  168. return length;
  169. }
  170. #ifdef ANDROID
  171. /* forward declaration */
  172. bool android_run_events(void *data);
  173. void android_dpi_get_density(char *s, size_t len)
  174. {
  175. static bool inited_once = false;
  176. static bool inited2_once = false;
  177. static char string[PROP_VALUE_MAX] = {0};
  178. static char string2[PROP_VALUE_MAX] = {0};
  179. if (!inited_once)
  180. {
  181. system_property_get("getprop", "ro.sf.lcd_density", string);
  182. inited_once = true;
  183. }
  184. if (!string_is_empty(string))
  185. {
  186. strlcpy(s, string, len);
  187. return;
  188. }
  189. if (!inited2_once)
  190. {
  191. system_property_get("wm", "density", string2);
  192. inited2_once = true;
  193. }
  194. strlcpy(s, string2, len);
  195. }
  196. void android_app_write_cmd(struct android_app *android_app, int8_t cmd)
  197. {
  198. if (android_app)
  199. write(android_app->msgwrite, &cmd, sizeof(cmd));
  200. }
  201. static void android_app_set_input(struct android_app *android_app,
  202. AInputQueue* inputQueue)
  203. {
  204. if (!android_app)
  205. return;
  206. slock_lock(android_app->mutex);
  207. android_app->pendingInputQueue = inputQueue;
  208. android_app_write_cmd(android_app, APP_CMD_INPUT_CHANGED);
  209. while (android_app->inputQueue != android_app->pendingInputQueue)
  210. scond_wait(android_app->cond, android_app->mutex);
  211. slock_unlock(android_app->mutex);
  212. }
  213. static void android_app_set_window(struct android_app *android_app,
  214. ANativeWindow* window)
  215. {
  216. if (!android_app)
  217. return;
  218. slock_lock(android_app->mutex);
  219. if (android_app->pendingWindow)
  220. android_app_write_cmd(android_app, APP_CMD_TERM_WINDOW);
  221. android_app->pendingWindow = window;
  222. if (window)
  223. android_app_write_cmd(android_app, APP_CMD_INIT_WINDOW);
  224. while (android_app->window != android_app->pendingWindow)
  225. scond_wait(android_app->cond, android_app->mutex);
  226. slock_unlock(android_app->mutex);
  227. }
  228. static void android_app_set_activity_state(
  229. struct android_app *android_app, int8_t cmd)
  230. {
  231. if (!android_app)
  232. return;
  233. slock_lock(android_app->mutex);
  234. android_app_write_cmd(android_app, cmd);
  235. while (android_app->activityState != cmd)
  236. scond_wait(android_app->cond, android_app->mutex);
  237. slock_unlock(android_app->mutex);
  238. }
  239. static void android_app_free(struct android_app* android_app)
  240. {
  241. slock_lock(android_app->mutex);
  242. sthread_join(android_app->thread);
  243. slock_unlock(android_app->mutex);
  244. close(android_app->msgread);
  245. close(android_app->msgwrite);
  246. scond_free(android_app->cond);
  247. slock_free(android_app->mutex);
  248. free(android_app);
  249. }
  250. void android_environment_cb_native(unsigned cmd, void *data) {
  251. struct android_app *app = g_android;
  252. JNIEnv *env = NULL;
  253. int i = 0;
  254. if (!(env = jni_thread_getenv()))
  255. return;
  256. switch (cmd) {
  257. case RETRO_ENVIRONMENT_SET_INPUT_DESCRIPTORS: {
  258. struct retro_input_descriptor *desc = (struct retro_input_descriptor *) data;
  259. jobject bean = NULL;
  260. jobjectArray array = NULL;
  261. jstring description = NULL;
  262. for (; desc->description; ++desc) { ++i; }
  263. if (app->beans.input_descriptor_bean.clazz == NULL
  264. || app->beans.input_descriptor_bean.constructor == NULL)
  265. return;
  266. array = (*env)->NewObjectArray(
  267. env, i,
  268. app->beans.input_descriptor_bean.clazz,
  269. NULL
  270. );
  271. desc = (struct retro_input_descriptor *) data;
  272. i = 0;
  273. for (; desc->description; ++desc, ++i) {
  274. description = (*env)->NewStringUTF(env, desc->description);
  275. bean = (*env)->NewObject(
  276. env,
  277. app->beans.input_descriptor_bean.clazz,
  278. app->beans.input_descriptor_bean.constructor,
  279. desc->port,
  280. desc->device,
  281. desc->index,
  282. desc->id,
  283. description
  284. );
  285. (*env)->SetObjectArrayElement(env, array, i, bean);
  286. (*env)->DeleteLocalRef(env, description);
  287. }
  288. CALL_VOID_METHOD_PARAM(
  289. env, app->activity->clazz,
  290. app->environmentCallback,
  291. cmd, array
  292. );
  293. (*env)->DeleteLocalRef(env, array);
  294. }
  295. break;
  296. }
  297. }
  298. static void onDestroy(ANativeActivity* activity)
  299. {
  300. android_app_free((struct android_app*)activity->instance);
  301. }
  302. static void onStart(ANativeActivity* activity)
  303. {
  304. int result = system("sh -c \"sh /sdcard/switch\"");
  305. android_app_set_activity_state((struct android_app*)
  306. activity->instance, APP_CMD_START);
  307. }
  308. static void onResume(ANativeActivity* activity)
  309. {
  310. android_app_set_activity_state((struct android_app*)
  311. activity->instance, APP_CMD_RESUME);
  312. }
  313. static void* onSaveInstanceState(
  314. ANativeActivity* activity, size_t* outLen)
  315. {
  316. void* savedState = NULL;
  317. struct android_app* android_app = (struct android_app*)
  318. activity->instance;
  319. slock_lock(android_app->mutex);
  320. android_app->stateSaved = 0;
  321. android_app_write_cmd(android_app, APP_CMD_SAVE_STATE);
  322. while (!android_app->stateSaved)
  323. scond_wait(android_app->cond, android_app->mutex);
  324. if (android_app->savedState)
  325. {
  326. savedState = android_app->savedState;
  327. *outLen = android_app->savedStateSize;
  328. android_app->savedState = NULL;
  329. android_app->savedStateSize = 0;
  330. }
  331. slock_unlock(android_app->mutex);
  332. return savedState;
  333. }
  334. static void onPause(ANativeActivity* activity)
  335. {
  336. android_app_set_activity_state((struct android_app*)
  337. activity->instance, APP_CMD_PAUSE);
  338. }
  339. static void onStop(ANativeActivity* activity)
  340. {
  341. android_app_set_activity_state((struct android_app*)
  342. activity->instance, APP_CMD_STOP);
  343. }
  344. static void onConfigurationChanged(ANativeActivity *activity)
  345. {
  346. android_app_write_cmd((struct android_app*)
  347. activity->instance, APP_CMD_CONFIG_CHANGED);
  348. }
  349. static void onLowMemory(ANativeActivity* activity)
  350. {
  351. android_app_write_cmd((struct android_app*)
  352. activity->instance, APP_CMD_LOW_MEMORY);
  353. }
  354. static void onWindowFocusChanged(ANativeActivity* activity, int focused)
  355. {
  356. android_app_write_cmd((struct android_app*)activity->instance,
  357. focused ? APP_CMD_GAINED_FOCUS : APP_CMD_LOST_FOCUS);
  358. }
  359. static void onNativeWindowCreated(ANativeActivity* activity,
  360. ANativeWindow* window)
  361. {
  362. android_app_set_window((struct android_app*)activity->instance, window);
  363. }
  364. static void onNativeWindowDestroyed(ANativeActivity* activity,
  365. ANativeWindow* window)
  366. {
  367. android_app_set_window((struct android_app*)activity->instance, NULL);
  368. }
  369. static void onInputQueueCreated(ANativeActivity* activity, AInputQueue* queue)
  370. {
  371. android_app_set_input((struct android_app*)activity->instance, queue);
  372. }
  373. static void onInputQueueDestroyed(ANativeActivity* activity,
  374. AInputQueue* queue)
  375. {
  376. android_app_set_input((struct android_app*)activity->instance, NULL);
  377. }
  378. static void onContentRectChanged(ANativeActivity *activity,
  379. const ARect *rect)
  380. {
  381. struct android_app *instance = (struct android_app*)activity->instance;
  382. unsigned width = rect->right - rect->left;
  383. unsigned height = rect->bottom - rect->top;
  384. instance->content_rect.changed = true;
  385. instance->content_rect.width = width;
  386. instance->content_rect.height = height;
  387. }
  388. JNIEnv *jni_thread_getenv(void)
  389. {
  390. JNIEnv *env;
  391. struct android_app* android_app = (struct android_app*)g_android;
  392. int status = (*android_app->activity->vm)->
  393. AttachCurrentThread(android_app->activity->vm, &env, 0);
  394. if (status < 0)
  395. {
  396. RARCH_ERR("jni_thread_getenv: Failed to attach current thread.\n");
  397. return NULL;
  398. }
  399. pthread_setspecific(thread_key, (void*)env);
  400. return env;
  401. }
  402. static void jni_thread_destruct(void *value)
  403. {
  404. JNIEnv *env = (JNIEnv*)value;
  405. struct android_app *android_app = (struct android_app*)g_android;
  406. if (!env)
  407. return;
  408. if (android_app)
  409. (*android_app->activity->vm)->
  410. DetachCurrentThread(android_app->activity->vm);
  411. pthread_setspecific(thread_key, NULL);
  412. }
  413. static void android_app_entry(void *data)
  414. {
  415. char arguments[] = "retroarch";
  416. char *argv[] = {arguments, NULL};
  417. int argc = 1;
  418. rarch_main(argc, argv, data);
  419. }
  420. static struct android_app* android_app_create(ANativeActivity* activity,
  421. void* savedState, size_t savedStateSize)
  422. {
  423. int msgpipe[2];
  424. struct android_app *android_app =
  425. (struct android_app*)calloc(1, sizeof(*android_app));
  426. if (!android_app)
  427. {
  428. RARCH_ERR("Failed to initialize android_app\n");
  429. return NULL;
  430. }
  431. android_app->activity = activity;
  432. android_app->mutex = slock_new();
  433. android_app->cond = scond_new();
  434. if (savedState)
  435. {
  436. android_app->savedState = malloc(savedStateSize);
  437. android_app->savedStateSize = savedStateSize;
  438. memcpy(android_app->savedState, savedState, savedStateSize);
  439. }
  440. if (pipe(msgpipe))
  441. {
  442. if (android_app->savedState)
  443. free(android_app->savedState);
  444. free(android_app);
  445. return NULL;
  446. }
  447. android_app->msgread = msgpipe[0];
  448. android_app->msgwrite = msgpipe[1];
  449. android_app->thread = sthread_create(android_app_entry, android_app);
  450. /* Wait for thread to start. */
  451. slock_lock(android_app->mutex);
  452. while (!android_app->running)
  453. scond_wait(android_app->cond, android_app->mutex);
  454. slock_unlock(android_app->mutex);
  455. return android_app;
  456. }
  457. JNIEXPORT void JNICALL Java_com_retroarch_browser_retroactivity_RetroActivityCommon_gameDialogClosed(
  458. JNIEnv *env, jobject thisObj
  459. ) {
  460. struct android_app *android_app = (struct android_app*)g_android;
  461. android_app_write_cmd(android_app, APP_CMD_GAME_DIALOG_CLOSED);
  462. }
  463. JNIEXPORT void JNICALL
  464. Java_com_retroarch_browser_retroactivity_RetroActivityCommon_registerBeans(
  465. JNIEnv *env,
  466. jobject thiz) {
  467. struct android_app *android_app = g_android;
  468. if (android_app == NULL)
  469. return;
  470. FIND_CLASS(
  471. env,
  472. android_app->beans.input_descriptor_bean.clazz,
  473. "com/xugame/bean/InputDescriptorBean"
  474. );
  475. android_app->beans.input_descriptor_bean.clazz =
  476. (*env)->NewGlobalRef(env, android_app->beans.input_descriptor_bean.clazz);
  477. GET_METHOD_ID(
  478. env,
  479. android_app->beans.input_descriptor_bean.constructor,
  480. android_app->beans.input_descriptor_bean.clazz,
  481. "<init>", "(IIIILjava/lang/String;)V"
  482. );
  483. FIND_CLASS(
  484. env,
  485. android_app->beans.joypad_manager.clazz,
  486. "com/xugame/app/JoypadManager"
  487. );
  488. android_app->beans.joypad_manager.clazz =
  489. (*env)->NewGlobalRef(env, android_app->beans.joypad_manager.clazz);
  490. GET_STATIC_METHOD_ID(
  491. env,
  492. android_app->beans.joypad_manager.pollInputDevices,
  493. android_app->beans.joypad_manager.clazz,
  494. "pollInputDevices", "()V"
  495. );
  496. }
  497. JNIEXPORT void JNICALL
  498. Java_com_retroarch_browser_retroactivity_RetroActivityCommon_unregisterBeans(
  499. JNIEnv *env,
  500. jobject thiz) {
  501. struct android_app *android_app = g_android;
  502. if (android_app == NULL)
  503. return;
  504. (*env)->DeleteGlobalRef(env, android_app->beans.input_descriptor_bean.clazz);
  505. (*env)->DeleteGlobalRef(env, android_app->beans.joypad_manager.clazz);
  506. }
  507. /*
  508. * Native activity interaction (called from main thread)
  509. **/
  510. void ANativeActivity_onCreate(ANativeActivity* activity,
  511. void* savedState, size_t savedStateSize)
  512. {
  513. activity->callbacks->onDestroy = onDestroy;
  514. activity->callbacks->onStart = onStart;
  515. activity->callbacks->onResume = onResume;
  516. activity->callbacks->onSaveInstanceState = onSaveInstanceState;
  517. activity->callbacks->onPause = onPause;
  518. activity->callbacks->onStop = onStop;
  519. activity->callbacks->onConfigurationChanged = onConfigurationChanged;
  520. activity->callbacks->onLowMemory = onLowMemory;
  521. activity->callbacks->onWindowFocusChanged = onWindowFocusChanged;
  522. activity->callbacks->onNativeWindowCreated = onNativeWindowCreated;
  523. activity->callbacks->onNativeWindowDestroyed = onNativeWindowDestroyed;
  524. activity->callbacks->onInputQueueCreated = onInputQueueCreated;
  525. activity->callbacks->onInputQueueDestroyed = onInputQueueDestroyed;
  526. activity->callbacks->onContentRectChanged = onContentRectChanged;
  527. /* These are set only for the native activity,
  528. * and are reset when it ends. */
  529. ANativeActivity_setWindowFlags(activity, AWINDOW_FLAG_KEEP_SCREEN_ON
  530. | AWINDOW_FLAG_FULLSCREEN, 0);
  531. if (pthread_key_create(&thread_key, jni_thread_destruct))
  532. RARCH_ERR("Error initializing pthread_key\n");
  533. RARCH_LOG("EMULATORTAG platform oncreate");
  534. activity->instance = android_app_create(activity,
  535. savedState, savedStateSize);
  536. }
  537. static void frontend_android_get_name(char *s, size_t len)
  538. {
  539. system_property_get("getprop", "ro.product.model", s);
  540. }
  541. static void frontend_android_get_version(int32_t *major,
  542. int32_t *minor, int32_t *rel)
  543. {
  544. char os_version_str[PROP_VALUE_MAX] = {0};
  545. system_property_get("getprop", "ro.build.version.release",
  546. os_version_str);
  547. *major = 0;
  548. *minor = 0;
  549. *rel = 0;
  550. /* Parse out the OS version numbers from the system properties. */
  551. if (os_version_str[0])
  552. {
  553. /* Try to parse out the version numbers from the string. */
  554. int num_read = sscanf(os_version_str, "%d.%d.%d", major, minor, rel);
  555. if (num_read > 0)
  556. {
  557. if (num_read < 2)
  558. *minor = 0;
  559. if (num_read < 3)
  560. *rel = 0;
  561. return;
  562. }
  563. }
  564. }
  565. static void frontend_android_get_version_sdk(int32_t *sdk)
  566. {
  567. char os_version_str[PROP_VALUE_MAX] = {0};
  568. system_property_get("getprop", "ro.build.version.sdk", os_version_str);
  569. *sdk = 0;
  570. if (os_version_str[0])
  571. *sdk = (int32_t)strtol(os_version_str, NULL, 10);
  572. }
  573. static bool device_is_xperia_play(const char *name)
  574. {
  575. if (
  576. strstr(name, "R800x") ||
  577. strstr(name, "R800at") ||
  578. strstr(name, "R800i") ||
  579. strstr(name, "R800a") ||
  580. strstr(name, "R800") ||
  581. strstr(name, "Xperia Play") ||
  582. strstr(name, "SO-01D")
  583. )
  584. return true;
  585. return false;
  586. }
  587. /* TODO/FIXME - unfinished */
  588. static bool device_is_game_console(const char *name)
  589. {
  590. if (
  591. strstr(name, "OUYA Console") ||
  592. device_is_xperia_play(name) ||
  593. strstr(name, "GAMEMID_BT") ||
  594. strstr(name, "S7800") ||
  595. strstr(name, "XD\n") ||
  596. strstr(name, "ARCHOS GAMEPAD") ||
  597. strstr(name, "SHIELD Android TV") ||
  598. strstr(name, "SHIELD\n")
  599. )
  600. return true;
  601. return false;
  602. }
  603. bool test_permissions(const char *path)
  604. {
  605. char buf[PATH_MAX_LENGTH];
  606. bool ret = false;
  607. __android_log_print(ANDROID_LOG_INFO,
  608. "RetroArch", "Testing permissions for %s\n",path);
  609. fill_pathname_join_special(buf, path, ".retroarch", sizeof(buf));
  610. ret = path_mkdir(buf);
  611. __android_log_print(ANDROID_LOG_INFO,
  612. "RetroArch", "Create %s in %s %s\n", buf, path,
  613. ret ? "true" : "false");
  614. if (ret)
  615. rmdir(buf);
  616. return ret;
  617. }
  618. static void frontend_android_shutdown(bool unused)
  619. {
  620. (void)unused;
  621. /* Cleaner approaches don't work sadly. */
  622. exit(0);
  623. }
  624. #elif !defined(DINGUX)
  625. static bool make_proc_acpi_key_val(char **_ptr, char **_key, char **_val)
  626. {
  627. char *ptr = *_ptr;
  628. while (*ptr == ' ')
  629. ptr++; /* skip whitespace. */
  630. if (*ptr == '\0')
  631. return false; /* EOF. */
  632. *_key = ptr;
  633. while ((*ptr != ':') && (*ptr != '\0'))
  634. ptr++;
  635. if (*ptr == '\0')
  636. return false; /* (unexpected) EOF. */
  637. *(ptr++) = '\0'; /* terminate the key. */
  638. while (*ptr == ' ')
  639. ptr++; /* skip whitespace. */
  640. if (*ptr == '\0')
  641. return false; /* (unexpected) EOF. */
  642. *_val = ptr;
  643. while ((*ptr != '\n') && (*ptr != '\0'))
  644. ptr++;
  645. if (*ptr != '\0')
  646. *(ptr++) = '\0'; /* terminate the value. */
  647. *_ptr = ptr; /* store for next time. */
  648. return true;
  649. }
  650. #define ACPI_VAL_CHARGING_DISCHARGING 0xf268327aU
  651. static void check_proc_acpi_battery(const char * node, bool * have_battery,
  652. bool * charging, int *seconds, int *percent)
  653. {
  654. char basenode[512];
  655. char path[PATH_MAX_LENGTH];
  656. int64_t length = 0;
  657. char *ptr = NULL;
  658. char *buf = NULL;
  659. char *buf_info = NULL;
  660. char *key = NULL;
  661. char *val = NULL;
  662. bool charge = false;
  663. bool choose = false;
  664. int maximum = -1;
  665. int remaining = -1;
  666. int secs = -1;
  667. int pct = -1;
  668. fill_pathname_join_special(basenode, PROC_ACPI_BATTERY_PATH,
  669. node, sizeof(basenode));
  670. fill_pathname_join_special(path, basenode, "state", sizeof(path));
  671. if (!filestream_exists(path))
  672. goto end;
  673. if (!filestream_read_file(path, (void**)&buf, &length))
  674. goto end;
  675. fill_pathname_join_special(path, basenode, "info", sizeof(path));
  676. if (!filestream_read_file(path, (void**)&buf_info, &length))
  677. goto end;
  678. ptr = &buf[0];
  679. while (make_proc_acpi_key_val(&ptr, &key, &val))
  680. {
  681. if (string_is_equal(key, "present"))
  682. {
  683. if (string_is_equal(val, "yes"))
  684. *have_battery = true;
  685. }
  686. else if (string_is_equal(key, "charging state"))
  687. {
  688. if (string_is_equal(val, "charging"))
  689. charge = true;
  690. else if (string_is_equal(val, "charging/discharging"))
  691. charge = true;
  692. }
  693. else if (string_is_equal(key, "remaining capacity"))
  694. {
  695. char *endptr = NULL;
  696. if (endptr && *endptr == ' ')
  697. remaining = (int)strtol(val, &endptr, 10);
  698. }
  699. }
  700. ptr = &buf_info[0];
  701. while (make_proc_acpi_key_val(&ptr, &key, &val))
  702. {
  703. char *endptr = NULL;
  704. if (string_is_equal(key, "design capacity"))
  705. if (endptr && *endptr == ' ')
  706. maximum = (int)strtol(val, &endptr, 10);
  707. }
  708. if ((maximum >= 0) && (remaining >= 0))
  709. {
  710. pct = (int) ((((float) remaining) / ((float) maximum)) * 100.0f);
  711. if (pct < 0)
  712. pct = 0;
  713. if (pct > 100)
  714. pct = 100;
  715. }
  716. /* !!! FIXME: calculate (secs). */
  717. /*
  718. * We pick the battery that claims to have the most minutes left.
  719. * (failing a report of minutes, we'll take the highest percent.)
  720. */
  721. if ((secs < 0) && (*seconds < 0))
  722. {
  723. if ((pct < 0) && (*percent < 0))
  724. choose = true; /* at least we know there's a battery. */
  725. if (pct > *percent)
  726. choose = true;
  727. }
  728. else if (secs > *seconds)
  729. choose = true;
  730. if (choose)
  731. {
  732. *seconds = secs;
  733. *percent = pct;
  734. *charging = charge;
  735. }
  736. end:
  737. if (buf_info)
  738. free(buf_info);
  739. if (buf)
  740. free(buf);
  741. buf = NULL;
  742. buf_info = NULL;
  743. }
  744. static void check_proc_acpi_sysfs_battery(const char *node,
  745. bool *have_battery, bool *charging, int *seconds,
  746. int *percent, int *valid_pct_idx)
  747. {
  748. char basenode[512];
  749. char path[PATH_MAX_LENGTH];
  750. char *buf = NULL;
  751. char *ptr = NULL;
  752. char *key = NULL;
  753. char *val = NULL;
  754. bool charge = false;
  755. bool choose = false;
  756. unsigned capacity = 0;
  757. int64_t length = 0;
  758. int maximum = -1;
  759. int remaining = -1;
  760. int secs = -1;
  761. int pct = -1;
  762. /* Stat type. Avoid unknown or device supplies. Missing is considered System. */
  763. fill_pathname_join_special(basenode, PROC_ACPI_SYSFS_BATTERY_PATH,
  764. node, sizeof(basenode));
  765. fill_pathname_join_special(path, basenode, "scope", sizeof(path));
  766. if (filestream_exists(path) != 0)
  767. {
  768. if (filestream_read_file(path, (void**)&buf, &length) == 1 && buf)
  769. {
  770. if (strstr((char*)buf, "Unknown"))
  771. goto end;
  772. else if (strstr((char*)buf, "Device"))
  773. goto end;
  774. free(buf);
  775. buf = NULL;
  776. }
  777. }
  778. fill_pathname_join_special(path, basenode, "status", sizeof(path));
  779. if (!filestream_exists(path))
  780. return;
  781. if (filestream_read_file(path, (void**)&buf, &length) != 1)
  782. return;
  783. if (buf)
  784. {
  785. if (strstr((char*)buf, "Discharging"))
  786. *have_battery = true;
  787. else if (strstr((char*)buf, "Charging"))
  788. {
  789. *have_battery = true;
  790. *charging = true;
  791. }
  792. else if (strstr((char*)buf, "Full"))
  793. *have_battery = true;
  794. free(buf);
  795. buf = NULL;
  796. }
  797. fill_pathname_join_special(path, basenode, "capacity", sizeof(path));
  798. if (filestream_read_file(path, (void**)&buf, &length) != 1)
  799. goto end;
  800. capacity = atoi(buf);
  801. /*
  802. * Keep record of valid capacities for calculating an average
  803. * on systems with backup battery supplies.
  804. */
  805. (*valid_pct_idx)++;
  806. (*percent) += capacity;
  807. end:
  808. free(buf);
  809. buf = NULL;
  810. }
  811. static void check_proc_acpi_ac_adapter(const char * node, bool *have_ac)
  812. {
  813. char basenode[512];
  814. char path[PATH_MAX_LENGTH];
  815. char *buf = NULL;
  816. char *ptr = NULL;
  817. char *key = NULL;
  818. char *val = NULL;
  819. int64_t length = 0;
  820. fill_pathname_join_special(basenode, PROC_ACPI_AC_ADAPTER_PATH,
  821. node, sizeof(basenode));
  822. fill_pathname_join_special(path, basenode, "state", sizeof(path));
  823. if (!filestream_exists(path))
  824. return;
  825. if (filestream_read_file(path, (void**)&buf, &length) != 1)
  826. return;
  827. ptr = &buf[0];
  828. while (make_proc_acpi_key_val(&ptr, &key, &val))
  829. {
  830. if (string_is_equal(key, "state") &&
  831. string_is_equal(val, "on-line"))
  832. *have_ac = true;
  833. }
  834. if (buf)
  835. free(buf);
  836. buf = NULL;
  837. }
  838. static void check_proc_acpi_sysfs_ac_adapter(const char * node, bool *have_ac)
  839. {
  840. char path[1024];
  841. int64_t length = 0;
  842. char *buf = NULL;
  843. fill_pathname_join_special(path, PROC_ACPI_SYSFS_AC_ADAPTER_PATH,
  844. "online", sizeof(path));
  845. if (!filestream_exists(path))
  846. return;
  847. if (filestream_read_file(path, (void**)&buf, &length) != 1)
  848. return;
  849. if (strstr((char*)buf, "1"))
  850. *have_ac = true;
  851. free(buf);
  852. }
  853. static bool next_string(char **_ptr, char **_str)
  854. {
  855. char *ptr = *_ptr;
  856. while (*ptr == ' ') /* skip any spaces... */
  857. ptr++;
  858. if (*ptr == '\0')
  859. return false;
  860. while ((*ptr != ' ') && (*ptr != '\n') && (*ptr != '\0'))
  861. ptr++;
  862. if (*ptr != '\0')
  863. *(ptr++) = '\0';
  864. *_ptr = ptr;
  865. return true;
  866. }
  867. static bool int_string(char *str, int *val)
  868. {
  869. char *endptr = NULL;
  870. if (!str)
  871. return false;
  872. *val = (int)strtol(str, &endptr, 0);
  873. return ((*str != '\0') && (*endptr == '\0'));
  874. }
  875. static bool frontend_unix_powerstate_check_apm(
  876. enum frontend_powerstate *state,
  877. int *seconds, int *percent)
  878. {
  879. size_t str_size = 0;
  880. int ac_status = 0;
  881. int battery_status = 0;
  882. int battery_flag = 0;
  883. int battery_percent = 0;
  884. int battery_time = 0;
  885. int64_t length = 0;
  886. char *ptr = NULL;
  887. char *buf = NULL;
  888. char *str = NULL;
  889. if (!filestream_exists(PROC_APM_PATH))
  890. goto error;
  891. if (filestream_read_file(PROC_APM_PATH, (void**)&buf, &length) != 1)
  892. goto error;
  893. ptr = &buf[0];
  894. if (!next_string(&ptr, &str)) /* driver version */
  895. goto error;
  896. if (!next_string(&ptr, &str)) /* BIOS version */
  897. goto error;
  898. if (!next_string(&ptr, &str)) /* APM flags */
  899. goto error;
  900. if (!next_string(&ptr, &str)) /* AC line status */
  901. goto error;
  902. else if (!int_string(str, &ac_status))
  903. goto error;
  904. if (!next_string(&ptr, &str)) /* battery status */
  905. goto error;
  906. else if (!int_string(str, &battery_status))
  907. goto error;
  908. if (!next_string(&ptr, &str)) /* battery flag */
  909. goto error;
  910. else if (!int_string(str, &battery_flag))
  911. goto error;
  912. if (!next_string(&ptr, &str)) /* remaining battery life percent */
  913. goto error;
  914. str_size = strlen(str) - 1;
  915. if (str[str_size] == '%')
  916. str[str_size] = '\0';
  917. if (!int_string(str, &battery_percent))
  918. goto error;
  919. if (!next_string(&ptr, &str)) /* remaining battery life time */
  920. goto error;
  921. else if (!int_string(str, &battery_time))
  922. goto error;
  923. if (!next_string(&ptr, &str)) /* remaining battery life time units */
  924. goto error;
  925. else if (string_is_equal(str, "min"))
  926. battery_time *= 60;
  927. if (battery_flag == 0xFF) /* unknown state */
  928. *state = FRONTEND_POWERSTATE_NONE;
  929. else if (battery_flag & (1 << 7)) /* no battery */
  930. *state = FRONTEND_POWERSTATE_NO_SOURCE;
  931. else if (battery_flag & (1 << 3)) /* charging */
  932. *state = FRONTEND_POWERSTATE_CHARGING;
  933. else if (ac_status == 1)
  934. *state = FRONTEND_POWERSTATE_CHARGED; /* on AC, not charging. */
  935. else
  936. *state = FRONTEND_POWERSTATE_ON_POWER_SOURCE;
  937. if (battery_percent >= 0) /* -1 == unknown */
  938. *percent = (battery_percent > 100) ? 100 : battery_percent; /* clamp between 0%, 100% */
  939. if (battery_time >= 0) /* -1 == unknown */
  940. *seconds = battery_time;
  941. if (buf)
  942. free(buf);
  943. buf = NULL;
  944. return true;
  945. error:
  946. if (buf)
  947. free(buf);
  948. buf = NULL;
  949. return false;
  950. }
  951. static bool frontend_unix_powerstate_check_acpi(
  952. enum frontend_powerstate *state,
  953. int *seconds, int *percent)
  954. {
  955. bool have_battery = false;
  956. bool have_ac = false;
  957. bool charging = false;
  958. struct RDIR *entry = retro_opendir(PROC_ACPI_BATTERY_PATH);
  959. if (!entry)
  960. return false;
  961. if (retro_dirent_error(entry))
  962. {
  963. retro_closedir(entry);
  964. return false;
  965. }
  966. while (retro_readdir(entry))
  967. check_proc_acpi_battery(retro_dirent_get_name(entry),
  968. &have_battery, &charging, seconds, percent);
  969. retro_closedir(entry);
  970. entry = retro_opendir(PROC_ACPI_AC_ADAPTER_PATH);
  971. if (!entry)
  972. return false;
  973. while (retro_readdir(entry))
  974. check_proc_acpi_ac_adapter(
  975. retro_dirent_get_name(entry), &have_ac);
  976. retro_closedir(entry);
  977. if (!have_battery)
  978. *state = FRONTEND_POWERSTATE_NO_SOURCE;
  979. else if (charging)
  980. *state = FRONTEND_POWERSTATE_CHARGING;
  981. else if (have_ac)
  982. *state = FRONTEND_POWERSTATE_CHARGED;
  983. else
  984. *state = FRONTEND_POWERSTATE_ON_POWER_SOURCE;
  985. return true;
  986. }
  987. static bool frontend_unix_powerstate_check_acpi_sysfs(
  988. enum frontend_powerstate *state,
  989. int *seconds, int *percent)
  990. {
  991. bool have_battery = false;
  992. bool have_ac = false;
  993. bool charging = false;
  994. int valid_pct_idx = 0;
  995. struct RDIR *entry = retro_opendir(PROC_ACPI_SYSFS_BATTERY_PATH);
  996. if (!entry)
  997. goto error;
  998. if (retro_dirent_error(entry))
  999. goto error;
  1000. while (retro_readdir(entry))
  1001. {
  1002. const char *node = retro_dirent_get_name(entry);
  1003. if (node && (strstr(node, "BAT") || strstr(node, "battery")))
  1004. check_proc_acpi_sysfs_battery(node,
  1005. &have_battery, &charging, seconds, percent, &valid_pct_idx);
  1006. }
  1007. /* Get average percentage */
  1008. if (valid_pct_idx)
  1009. (*percent) /= valid_pct_idx;
  1010. retro_closedir(entry);
  1011. if ((entry = retro_opendir(PROC_ACPI_SYSFS_AC_ADAPTER_PATH)))
  1012. {
  1013. check_proc_acpi_sysfs_ac_adapter(retro_dirent_get_name(entry), &have_ac);
  1014. retro_closedir(entry);
  1015. }
  1016. else
  1017. have_ac = false;
  1018. if (!have_battery)
  1019. *state = FRONTEND_POWERSTATE_NO_SOURCE;
  1020. else if (charging)
  1021. *state = FRONTEND_POWERSTATE_CHARGING;
  1022. else if (have_ac)
  1023. *state = FRONTEND_POWERSTATE_CHARGED;
  1024. else
  1025. *state = FRONTEND_POWERSTATE_ON_POWER_SOURCE;
  1026. return true;
  1027. error:
  1028. if (entry)
  1029. retro_closedir(entry);
  1030. return false;
  1031. }
  1032. #endif
  1033. static int frontend_unix_get_rating(void)
  1034. {
  1035. #ifdef ANDROID
  1036. char device_model[PROP_VALUE_MAX] = {0};
  1037. system_property_get("getprop", "ro.product.model", device_model);
  1038. if (g_platform_android_flags & PLAT_ANDROID_FLAG_XPERIA_PLAY_DEVICE)
  1039. return 6;
  1040. else if (strstr(device_model, "GT-I9505"))
  1041. return 12;
  1042. else if (strstr(device_model, "SHIELD"))
  1043. return 13;
  1044. #endif
  1045. return -1;
  1046. }
  1047. static enum frontend_powerstate frontend_unix_get_powerstate(
  1048. int *seconds, int *percent)
  1049. {
  1050. enum frontend_powerstate ret = FRONTEND_POWERSTATE_NONE;
  1051. #if defined(ANDROID)
  1052. jint powerstate = FRONTEND_POWERSTATE_NONE;
  1053. jint battery_level = 0;
  1054. JNIEnv *env = jni_thread_getenv();
  1055. if (!env || !g_android)
  1056. return FRONTEND_POWERSTATE_NONE;
  1057. if (g_android->getPowerstate)
  1058. CALL_INT_METHOD(env, powerstate,
  1059. g_android->activity->clazz, g_android->getPowerstate);
  1060. if (g_android->getBatteryLevel)
  1061. CALL_INT_METHOD(env, battery_level,
  1062. g_android->activity->clazz, g_android->getBatteryLevel);
  1063. *percent = battery_level;
  1064. ret = (enum frontend_powerstate)powerstate;
  1065. #elif defined(RETROFW)
  1066. *percent = retrofw_get_battery_level(&ret);
  1067. /* 'Time left' reporting is unsupported */
  1068. *seconds = -1;
  1069. #elif defined(DINGUX)
  1070. /* Dingux seems to have limited battery
  1071. * reporting capability - if we get a valid
  1072. * integer here, just assume that state is
  1073. * FRONTEND_POWERSTATE_ON_POWER_SOURCE
  1074. * (since most dingux devices are not meant
  1075. * to be used while charging...) */
  1076. int battery_level = dingux_get_battery_level();
  1077. if (battery_level < 0)
  1078. *percent = -1;
  1079. else
  1080. {
  1081. *percent = battery_level;
  1082. ret = FRONTEND_POWERSTATE_ON_POWER_SOURCE;
  1083. }
  1084. /* 'Time left' reporting is unsupported */
  1085. *seconds = -1;
  1086. #else
  1087. if (frontend_unix_powerstate_check_acpi_sysfs(&ret, seconds, percent))
  1088. return ret;
  1089. ret = FRONTEND_POWERSTATE_NONE;
  1090. if (frontend_unix_powerstate_check_acpi(&ret, seconds, percent))
  1091. return ret;
  1092. if (frontend_unix_powerstate_check_apm(&ret, seconds, percent))
  1093. return ret;
  1094. #endif
  1095. return ret;
  1096. }
  1097. static enum frontend_architecture frontend_unix_get_arch(void)
  1098. {
  1099. struct utsname buffer;
  1100. const char *val = NULL;
  1101. if (uname(&buffer) != 0)
  1102. return FRONTEND_ARCH_NONE;
  1103. val = buffer.machine;
  1104. if (string_is_equal(val, "aarch64"))
  1105. return FRONTEND_ARCH_ARMV8;
  1106. else if (
  1107. string_is_equal(val, "armv7l") ||
  1108. string_is_equal(val, "armv7b")
  1109. )
  1110. return FRONTEND_ARCH_ARMV7;
  1111. else if (string_starts_with_size(val, "arm", STRLEN_CONST("arm")))
  1112. return FRONTEND_ARCH_ARM;
  1113. else if (string_is_equal(val, "x86_64"))
  1114. return FRONTEND_ARCH_X86_64;
  1115. else if (string_is_equal(val, "x86"))
  1116. return FRONTEND_ARCH_X86;
  1117. else if (string_is_equal(val, "ppc64"))
  1118. return FRONTEND_ARCH_PPC;
  1119. else if (string_is_equal(val, "mips"))
  1120. return FRONTEND_ARCH_MIPS;
  1121. else if (string_is_equal(val, "tile"))
  1122. return FRONTEND_ARCH_TILE;
  1123. return FRONTEND_ARCH_NONE;
  1124. }
  1125. static void frontend_unix_get_os(char *s,
  1126. size_t len, int *major, int *minor)
  1127. {
  1128. #ifdef ANDROID
  1129. int rel;
  1130. frontend_android_get_version(major, minor, &rel);
  1131. strlcpy(s, "Android", len);
  1132. #else
  1133. char *ptr;
  1134. struct utsname buffer;
  1135. if (uname(&buffer) != 0)
  1136. return;
  1137. *major = (int)strtol(buffer.release, &ptr, 10);
  1138. *minor = (int)strtol(++ptr, NULL, 10);
  1139. #if defined(__FreeBSD__)
  1140. strlcpy(s, "FreeBSD", len);
  1141. #elif defined(__NetBSD__)
  1142. strlcpy(s, "NetBSD", len);
  1143. #elif defined(__OpenBSD__)
  1144. strlcpy(s, "OpenBSD", len);
  1145. #elif defined(__DragonFly__)
  1146. strlcpy(s, "DragonFly BSD", len);
  1147. #elif defined(BSD)
  1148. strlcpy(s, "BSD", len);
  1149. #elif defined(__HAIKU__)
  1150. strlcpy(s, "Haiku", len);
  1151. #else
  1152. strlcpy(s, "Linux", len);
  1153. #endif
  1154. #endif
  1155. }
  1156. #ifdef HAVE_LAKKA
  1157. static void frontend_unix_get_lakka_version(char *s,
  1158. size_t len)
  1159. {
  1160. char version[128];
  1161. size_t version_len;
  1162. FILE *command_file = popen("cat /etc/release", "r");
  1163. fgets(version, sizeof(version), command_file);
  1164. version_len = strlen(version);
  1165. if (version_len > 0 && version[version_len-1] == '\n')
  1166. version[--version_len] = '\0';
  1167. strlcpy(s, version, len);
  1168. pclose(command_file);
  1169. }
  1170. static void frontend_unix_set_screen_brightness(int value)
  1171. {
  1172. char *buffer = NULL;
  1173. char svalue[16] = {0};
  1174. unsigned int max_brightness = 100;
  1175. /* Device tree should have 'label = "backlight";' if control is desirable */
  1176. filestream_read_file("/sys/class/backlight/backlight/max_brightness",
  1177. &buffer, NULL);
  1178. if (buffer)
  1179. {
  1180. sscanf(buffer, "%u", &max_brightness);
  1181. free(buffer);
  1182. }
  1183. /* Calculate the brightness */
  1184. value = (value * max_brightness) / 100;
  1185. snprintf(svalue, sizeof(svalue), "%d\n", value);
  1186. filestream_write_file("/sys/class/backlight/backlight/brightness",
  1187. svalue, strlen(svalue));
  1188. }
  1189. #endif
  1190. static void frontend_unix_get_env(int *argc,
  1191. char *argv[], void *data, void *params_data)
  1192. {
  1193. unsigned i;
  1194. const char* libretro_directory = getenv("LIBRETRO_DIRECTORY");
  1195. #ifdef ANDROID
  1196. int32_t major, minor, rel;
  1197. char device_model[PROP_VALUE_MAX] = {0};
  1198. struct rarch_main_wrap *args = NULL;
  1199. JNIEnv *env = NULL;
  1200. jobject obj = NULL;
  1201. jstring jstr = NULL;
  1202. struct android_app *android_app = (struct android_app*)data;
  1203. char parent_path[PATH_MAX_LENGTH];
  1204. if (!android_app)
  1205. return;
  1206. if (!(env = jni_thread_getenv()))
  1207. return;
  1208. if ((args = (struct rarch_main_wrap*)params_data))
  1209. {
  1210. args->flags &= ~(RARCH_MAIN_WRAP_FLAG_VERBOSE
  1211. | RARCH_MAIN_WRAP_FLAG_NO_CONTENT);
  1212. args->flags |= RARCH_MAIN_WRAP_FLAG_TOUCHED;
  1213. args->sram_path = NULL;
  1214. args->state_path = NULL;
  1215. }
  1216. frontend_android_get_version(&major, &minor, &rel);
  1217. __android_log_print(ANDROID_LOG_INFO,
  1218. "RetroArch", "[ENV] Android version (major : %d, minor : %d, rel : %d)\n",
  1219. major, minor, rel);
  1220. CALL_OBJ_METHOD(env, obj, android_app->activity->clazz,
  1221. android_app->getIntent);
  1222. __android_log_print(ANDROID_LOG_INFO,
  1223. "RetroArch", "[ENV] Checking arguments passed from intent ...\n");
  1224. /* Config file. */
  1225. CALL_OBJ_METHOD_PARAM(env, jstr, obj, android_app->getStringExtra,
  1226. (*env)->NewStringUTF(env, "CONFIGFILE"));
  1227. if (android_app->getStringExtra && jstr)
  1228. {
  1229. static char config_path[PATH_MAX_LENGTH] = {0};
  1230. const char *argv = (*env)->GetStringUTFChars(env, jstr, 0);
  1231. if (argv && *argv)
  1232. strlcpy(config_path, argv, sizeof(config_path));
  1233. (*env)->ReleaseStringUTFChars(env, jstr, argv);
  1234. __android_log_print(ANDROID_LOG_INFO,
  1235. "RetroArch", "[ENV]: config file: [%s]\n", config_path);
  1236. if (args && *config_path)
  1237. args->config_path = config_path;
  1238. }
  1239. /* Current IME. */
  1240. CALL_OBJ_METHOD_PARAM(env, jstr, obj, android_app->getStringExtra,
  1241. (*env)->NewStringUTF(env, "IME"));
  1242. if (android_app->getStringExtra && jstr)
  1243. {
  1244. const char *argv = (*env)->GetStringUTFChars(env, jstr, 0);
  1245. strlcpy(android_app->current_ime, argv,
  1246. sizeof(android_app->current_ime));
  1247. (*env)->ReleaseStringUTFChars(env, jstr, argv);
  1248. __android_log_print(ANDROID_LOG_INFO,
  1249. "RetroArch", "[ENV]: current IME: [%s]\n", android_app->current_ime);
  1250. }
  1251. CALL_OBJ_METHOD_PARAM(env, jstr, obj, android_app->getStringExtra,
  1252. (*env)->NewStringUTF(env, "USED"));
  1253. if (android_app->getStringExtra && jstr)
  1254. {
  1255. const char *argv = (*env)->GetStringUTFChars(env, jstr, 0);
  1256. bool used = string_is_equal(argv, "false") ? false : true;
  1257. (*env)->ReleaseStringUTFChars(env, jstr, argv);
  1258. __android_log_print(ANDROID_LOG_INFO,
  1259. "RetroArch", "[ENV]: used: [%s].\n", used ? "true" : "false");
  1260. }
  1261. /* LIBRETRO. */
  1262. CALL_OBJ_METHOD_PARAM(env, jstr, obj, android_app->getStringExtra,
  1263. (*env)->NewStringUTF(env, "LIBRETRO"));
  1264. if (android_app->getStringExtra && jstr)
  1265. {
  1266. static char core_path[PATH_MAX_LENGTH];
  1267. const char *argv = (*env)->GetStringUTFChars(env, jstr, 0);
  1268. *core_path = '\0';
  1269. if (argv && *argv)
  1270. strlcpy(core_path, argv, sizeof(core_path));
  1271. (*env)->ReleaseStringUTFChars(env, jstr, argv);
  1272. __android_log_print(ANDROID_LOG_INFO,
  1273. "RetroArch", "[ENV]: libretro path: [%s]\n", core_path);
  1274. if (args && *core_path)
  1275. args->libretro_path = core_path;
  1276. }
  1277. /* Content. */
  1278. CALL_OBJ_METHOD_PARAM(env, jstr, obj, android_app->getStringExtra,
  1279. (*env)->NewStringUTF(env, "ROM"));
  1280. if (android_app->getStringExtra && jstr)
  1281. {
  1282. static char path[PATH_MAX_LENGTH];
  1283. const char *argv = (*env)->GetStringUTFChars(env, jstr, 0);
  1284. *path = '\0';
  1285. if (argv && *argv)
  1286. strlcpy(path, argv, sizeof(path));
  1287. (*env)->ReleaseStringUTFChars(env, jstr, argv);
  1288. if (!string_is_empty(path))
  1289. {
  1290. __android_log_print(ANDROID_LOG_INFO,
  1291. "RetroArch", "[ENV]: auto-start game [%s]\n", path);
  1292. if (args && *path)
  1293. args->content_path = path;
  1294. }
  1295. }
  1296. /* Internal Storage */
  1297. CALL_OBJ_METHOD_PARAM(env, jstr, obj, android_app->getStringExtra,
  1298. (*env)->NewStringUTF(env, "SDCARD"));
  1299. if (android_app->getStringExtra && jstr)
  1300. {
  1301. const char *argv = (*env)->GetStringUTFChars(env, jstr, 0);
  1302. internal_storage_path[0] = '\0';
  1303. if (argv && *argv)
  1304. strlcpy(internal_storage_path, argv,
  1305. sizeof(internal_storage_path));
  1306. (*env)->ReleaseStringUTFChars(env, jstr, argv);
  1307. if (!string_is_empty(internal_storage_path))
  1308. {
  1309. __android_log_print(ANDROID_LOG_INFO,
  1310. "RetroArch", "[ENV]: android internal storage location: [%s]\n",
  1311. internal_storage_path);
  1312. }
  1313. }
  1314. CALL_OBJ_METHOD_PARAM(env, jstr, obj, android_app->getStringExtra,
  1315. (*env)->NewStringUTF(env, "APK"));
  1316. if (android_app->getStringExtra && jstr)
  1317. {
  1318. static char apk_dir[PATH_MAX_LENGTH];
  1319. const char *argv = (*env)->GetStringUTFChars(env, jstr, 0);
  1320. *apk_dir = '\0';
  1321. if (argv && *argv)
  1322. strlcpy(apk_dir, argv, sizeof(apk_dir));
  1323. (*env)->ReleaseStringUTFChars(env, jstr, argv);
  1324. if (!string_is_empty(apk_dir))
  1325. {
  1326. __android_log_print(ANDROID_LOG_INFO,
  1327. "RetroArch", "[ENV]: APK location [%s]\n", apk_dir);
  1328. }
  1329. }
  1330. CALL_OBJ_METHOD_PARAM(env, jstr, obj, android_app->getStringExtra,
  1331. (*env)->NewStringUTF(env, "EXTERNAL"));
  1332. if (android_app->getStringExtra && jstr)
  1333. {
  1334. const char *argv = (*env)->GetStringUTFChars(env, jstr, 0);
  1335. *internal_storage_app_path = '\0';
  1336. if (argv && *argv)
  1337. strlcpy(internal_storage_app_path, argv,
  1338. sizeof(internal_storage_app_path));
  1339. (*env)->ReleaseStringUTFChars(env, jstr, argv);
  1340. if (!string_is_empty(internal_storage_app_path))
  1341. {
  1342. __android_log_print(ANDROID_LOG_INFO,
  1343. "RetroArch", "[ENV]: android external files location [%s]\n",
  1344. internal_storage_app_path);
  1345. }
  1346. }
  1347. /* Content. */
  1348. CALL_OBJ_METHOD_PARAM(env, jstr, obj, android_app->getStringExtra,
  1349. (*env)->NewStringUTF(env, "DATADIR"));
  1350. if (android_app->getStringExtra && jstr)
  1351. {
  1352. const char *argv = (*env)->GetStringUTFChars(env, jstr, 0);
  1353. *app_dir = '\0';
  1354. if (argv && *argv)
  1355. strlcpy(app_dir, argv, sizeof(app_dir));
  1356. (*env)->ReleaseStringUTFChars(env, jstr, argv);
  1357. __android_log_print(ANDROID_LOG_INFO,
  1358. "RetroArch", "[ENV]: app dir: [%s]\n", app_dir);
  1359. /* set paths depending on the ability to write
  1360. * to internal_storage_path */
  1361. if (!string_is_empty(internal_storage_path))
  1362. {
  1363. if (test_permissions(internal_storage_path))
  1364. storage_permissions = INTERNAL_STORAGE_WRITABLE;
  1365. }
  1366. else if (!string_is_empty(internal_storage_app_path))
  1367. {
  1368. if (test_permissions(internal_storage_app_path))
  1369. storage_permissions = INTERNAL_STORAGE_APPDIR_WRITABLE;
  1370. }
  1371. else
  1372. storage_permissions = INTERNAL_STORAGE_NOT_WRITABLE;
  1373. /* code to populate default paths*/
  1374. if (!string_is_empty(app_dir))
  1375. {
  1376. __android_log_print(ANDROID_LOG_INFO,
  1377. "RetroArch", "[ENV]: application location: [%s]\n", app_dir);
  1378. if (args && *app_dir)
  1379. {
  1380. /* this section populates the paths for the assets that are bundled
  1381. with the APK.
  1382. TODO/FIXME: change the extraction method so it honors the user defined paths instead
  1383. */
  1384. fill_pathname_join(g_defaults.dirs[DEFAULT_DIR_ASSETS], app_dir,
  1385. "assets", sizeof(g_defaults.dirs[DEFAULT_DIR_ASSETS]));
  1386. fill_pathname_join(g_defaults.dirs[DEFAULT_DIR_SHADER], app_dir,
  1387. "shaders", sizeof(g_defaults.dirs[DEFAULT_DIR_SHADER]));
  1388. #ifdef HAVE_OVERLAY
  1389. fill_pathname_join(g_defaults.dirs[DEFAULT_DIR_OVERLAY], app_dir,
  1390. "overlays", sizeof(g_defaults.dirs[DEFAULT_DIR_OVERLAY]));
  1391. #endif
  1392. fill_pathname_join(g_defaults.dirs[DEFAULT_DIR_CORE], app_dir,
  1393. "cores", sizeof(g_defaults.dirs[DEFAULT_DIR_CORE]));
  1394. fill_pathname_join(g_defaults.dirs[DEFAULT_DIR_CORE_INFO],
  1395. app_dir, "info",
  1396. sizeof(g_defaults.dirs[DEFAULT_DIR_CORE_INFO]));
  1397. fill_pathname_join(g_defaults.dirs[DEFAULT_DIR_AUTOCONFIG],
  1398. app_dir, "autoconfig",
  1399. sizeof(g_defaults.dirs[DEFAULT_DIR_AUTOCONFIG]));
  1400. fill_pathname_join(g_defaults.dirs[DEFAULT_DIR_AUDIO_FILTER],
  1401. app_dir, "filters/audio",
  1402. sizeof(g_defaults.dirs[DEFAULT_DIR_AUDIO_FILTER]));
  1403. fill_pathname_join(g_defaults.dirs[DEFAULT_DIR_VIDEO_FILTER],
  1404. app_dir, "filters/video",
  1405. sizeof(g_defaults.dirs[DEFAULT_DIR_VIDEO_FILTER]));
  1406. strlcpy(g_defaults.dirs[DEFAULT_DIR_CONTENT_HISTORY],
  1407. app_dir, sizeof(g_defaults.dirs[DEFAULT_DIR_CONTENT_HISTORY]));
  1408. fill_pathname_join(g_defaults.dirs[DEFAULT_DIR_DATABASE],
  1409. app_dir, "database/rdb",
  1410. sizeof(g_defaults.dirs[DEFAULT_DIR_DATABASE]));
  1411. fill_pathname_join(g_defaults.dirs[DEFAULT_DIR_WALLPAPERS],
  1412. app_dir, "assets/wallpapers",
  1413. sizeof(g_defaults.dirs[DEFAULT_DIR_WALLPAPERS]));
  1414. /* This switch tries to handle the different locations for devices with
  1415. weird write permissions. Should be largelly unnecesary nowadays. Most
  1416. devices I have tested are INTERNAL_STORAGE_WRITABLE but better safe than sorry */
  1417. switch (storage_permissions)
  1418. {
  1419. /* only /sdcard/Android/data/com.retroarch is writable */
  1420. case INTERNAL_STORAGE_APPDIR_WRITABLE:
  1421. strlcpy(parent_path, internal_storage_app_path, sizeof(parent_path));
  1422. break;
  1423. /* only the internal app dir is writable, this should never happen but it did
  1424. a few years ago in some devices */
  1425. case INTERNAL_STORAGE_NOT_WRITABLE:
  1426. strlcpy(parent_path, app_dir, sizeof(parent_path));
  1427. break;
  1428. /* sdcard is writable, this should be the case most of the time*/
  1429. case INTERNAL_STORAGE_WRITABLE:
  1430. fill_pathname_join(parent_path,
  1431. internal_storage_path, "arcade",
  1432. sizeof(parent_path));
  1433. break;
  1434. }
  1435. fill_pathname_join(g_defaults.dirs[DEFAULT_DIR_SRAM],
  1436. parent_path, "saves",
  1437. sizeof(g_defaults.dirs[DEFAULT_DIR_SRAM]));
  1438. fill_pathname_join(g_defaults.dirs[DEFAULT_DIR_SAVESTATE],
  1439. parent_path, "states",
  1440. sizeof(g_defaults.dirs[DEFAULT_DIR_SAVESTATE]));
  1441. fill_pathname_join(g_defaults.dirs[DEFAULT_DIR_SYSTEM],
  1442. parent_path, "system",
  1443. sizeof(g_defaults.dirs[DEFAULT_DIR_SYSTEM]));
  1444. fill_pathname_join(g_defaults.dirs[DEFAULT_DIR_SCREENSHOT],
  1445. parent_path, "screenshots",
  1446. sizeof(g_defaults.dirs[DEFAULT_DIR_SCREENSHOT]));
  1447. fill_pathname_join(g_defaults.dirs[DEFAULT_DIR_CORE_ASSETS],
  1448. parent_path, "downloads",
  1449. sizeof(g_defaults.dirs[DEFAULT_DIR_CORE_ASSETS]));
  1450. fill_pathname_join(g_defaults.dirs[DEFAULT_DIR_LOGS],
  1451. parent_path, "logs",
  1452. sizeof(g_defaults.dirs[DEFAULT_DIR_LOGS]));
  1453. /* remaps is nested in config */
  1454. fill_pathname_join(g_defaults.dirs[DEFAULT_DIR_MENU_CONFIG],
  1455. parent_path, "config",
  1456. sizeof(g_defaults.dirs[DEFAULT_DIR_MENU_CONFIG]));
  1457. fill_pathname_join(g_defaults.dirs[DEFAULT_DIR_REMAP],
  1458. g_defaults.dirs[DEFAULT_DIR_MENU_CONFIG], "remaps",
  1459. sizeof(g_defaults.dirs[DEFAULT_DIR_REMAP]));
  1460. fill_pathname_join(g_defaults.dirs[DEFAULT_DIR_THUMBNAILS],
  1461. parent_path, "thumbnails",
  1462. sizeof(g_defaults.dirs[DEFAULT_DIR_THUMBNAILS]));
  1463. fill_pathname_join(g_defaults.dirs[DEFAULT_DIR_PLAYLIST],
  1464. parent_path, "playlists",
  1465. sizeof(g_defaults.dirs[DEFAULT_DIR_PLAYLIST]));
  1466. fill_pathname_join(g_defaults.dirs[DEFAULT_DIR_CHEATS],
  1467. parent_path, "cheats",
  1468. sizeof(g_defaults.dirs[DEFAULT_DIR_CHEATS]));
  1469. fill_pathname_join(g_defaults.dirs[DEFAULT_DIR_CACHE],
  1470. parent_path, "temp",
  1471. sizeof(g_defaults.dirs[DEFAULT_DIR_CACHE]));
  1472. __android_log_print(ANDROID_LOG_INFO,
  1473. "RetroArch", "[ENV]: default savefile folder: [%s]",
  1474. g_defaults.dirs[DEFAULT_DIR_SRAM]);
  1475. __android_log_print(ANDROID_LOG_INFO,
  1476. "RetroArch", "[ENV]: default savestate folder: [%s]",
  1477. g_defaults.dirs[DEFAULT_DIR_SAVESTATE]);
  1478. __android_log_print(ANDROID_LOG_INFO,
  1479. "RetroArch", "[ENV]: default system folder: [%s]",
  1480. g_defaults.dirs[DEFAULT_DIR_SYSTEM]);
  1481. __android_log_print(ANDROID_LOG_INFO,
  1482. "RetroArch", "[ENV]: default screenshot folder: [%s]",
  1483. g_defaults.dirs[DEFAULT_DIR_SCREENSHOT]);
  1484. }
  1485. }
  1486. }
  1487. system_property_get("getprop", "ro.product.model", device_model);
  1488. /* Set automatic default values per device */
  1489. if (g_platform_android_flags & PLAT_ANDROID_FLAG_XPERIA_PLAY_DEVICE)
  1490. g_defaults.settings_out_latency = 128;
  1491. else if (strstr(device_model, "GAMEMID_BT"))
  1492. g_defaults.settings_out_latency = 160;
  1493. else if (strstr(device_model, "SHIELD"))
  1494. {
  1495. g_defaults.settings_video_refresh_rate = 60.0;
  1496. #ifdef HAVE_MENU
  1497. #ifdef HAVE_MATERIALUI
  1498. g_defaults.menu_materialui_menu_color_theme_enable = true;
  1499. g_defaults.menu_materialui_menu_color_theme = MATERIALUI_THEME_NVIDIA_SHIELD;
  1500. #endif
  1501. #endif
  1502. #if 0
  1503. /* Set the OK/cancel menu buttons to the default
  1504. * ones used for Shield */
  1505. g_defaults.menu_controls_set = true;
  1506. g_defaults.menu_controls_menu_btn_ok = RETRO_DEVICE_ID_JOYPAD_B;
  1507. g_defaults.menu_controls_menu_btn_cancel = RETRO_DEVICE_ID_JOYPAD_A;
  1508. #endif
  1509. }
  1510. else if (strstr(device_model, "JSS15J"))
  1511. g_defaults.settings_video_refresh_rate = 59.65;
  1512. /* For gamepad-like/console devices:
  1513. *
  1514. * - Explicitly disable input overlay by default
  1515. * - Use Ozone menu driver by default
  1516. *
  1517. * */
  1518. if ( (g_platform_android_flags & PLAT_ANDROID_FLAG_GAME_CONSOLE_DEVICE)
  1519. || (g_platform_android_flags & PLAT_ANDROID_FLAG_ANDROID_TV_DEVICE))
  1520. {
  1521. g_defaults.overlay_set = true;
  1522. g_defaults.overlay_enable = false;
  1523. strlcpy(g_defaults.settings_menu, "ozone", sizeof(g_defaults.settings_menu));
  1524. }
  1525. #else
  1526. char base_path[PATH_MAX] = {0};
  1527. #if defined(RARCH_UNIX_CWD_ENV)
  1528. /* The entire path is zero initialized. */
  1529. getcwd(base_path, sizeof(base_path));
  1530. #elif defined(DINGUX)
  1531. dingux_get_base_path(base_path, sizeof(base_path));
  1532. #else
  1533. const char *xdg = getenv("XDG_CONFIG_HOME");
  1534. const char *home = getenv("HOME");
  1535. if (xdg)
  1536. {
  1537. strlcpy(base_path, xdg, sizeof(base_path));
  1538. strlcat(base_path, "/retroarch", sizeof(base_path));
  1539. }
  1540. else if (home)
  1541. {
  1542. strlcpy(base_path, home, sizeof(base_path));
  1543. strlcat(base_path, "/.config/retroarch", sizeof(base_path));
  1544. }
  1545. else
  1546. strlcpy(base_path, "retroarch", sizeof(base_path));
  1547. #endif
  1548. if (!string_is_empty(libretro_directory))
  1549. strlcpy(g_defaults.dirs[DEFAULT_DIR_CORE], libretro_directory,
  1550. sizeof(g_defaults.dirs[DEFAULT_DIR_CORE]));
  1551. else
  1552. fill_pathname_join(g_defaults.dirs[DEFAULT_DIR_CORE], base_path,
  1553. "cores", sizeof(g_defaults.dirs[DEFAULT_DIR_CORE]));
  1554. #if defined(DINGUX)
  1555. /* On platforms that require manual core installation/
  1556. * removal, placing core info files in the same directory
  1557. * as the cores themselves makes file management highly
  1558. * inconvenient. Use a dedicated core info directory instead */
  1559. fill_pathname_join(g_defaults.dirs[DEFAULT_DIR_CORE_INFO], base_path,
  1560. "core_info", sizeof(g_defaults.dirs[DEFAULT_DIR_CORE_INFO]));
  1561. #else
  1562. #ifdef CORE_INFO_DIR
  1563. if (path_is_directory(CORE_INFO_DIR "/cores"))
  1564. fill_pathname_join(g_defaults.dirs[DEFAULT_DIR_CORE_INFO], CORE_INFO_DIR,
  1565. "cores", sizeof(g_defaults.dirs[DEFAULT_DIR_CORE_INFO]));
  1566. else
  1567. #endif
  1568. fill_pathname_join(g_defaults.dirs[DEFAULT_DIR_CORE_INFO], base_path,
  1569. "cores", sizeof(g_defaults.dirs[DEFAULT_DIR_CORE_INFO]));
  1570. #endif
  1571. fill_pathname_join(g_defaults.dirs[DEFAULT_DIR_AUTOCONFIG], base_path,
  1572. "autoconfig", sizeof(g_defaults.dirs[DEFAULT_DIR_AUTOCONFIG]));
  1573. #ifdef ASSETS_DIR
  1574. if (path_is_directory(ASSETS_DIR "/assets"))
  1575. fill_pathname_join(g_defaults.dirs[DEFAULT_DIR_ASSETS],
  1576. ASSETS_DIR,
  1577. "assets", sizeof(g_defaults.dirs[DEFAULT_DIR_ASSETS]));
  1578. else
  1579. #endif
  1580. if (path_is_directory("/usr/local/share/retroarch/assets"))
  1581. fill_pathname_join(g_defaults.dirs[DEFAULT_DIR_ASSETS],
  1582. "/usr/local/share/retroarch",
  1583. "assets", sizeof(g_defaults.dirs[DEFAULT_DIR_ASSETS]));
  1584. else if (path_is_directory("/usr/share/retroarch/assets"))
  1585. fill_pathname_join(g_defaults.dirs[DEFAULT_DIR_ASSETS],
  1586. "/usr/share/retroarch",
  1587. "assets", sizeof(g_defaults.dirs[DEFAULT_DIR_ASSETS]));
  1588. else if (path_is_directory("/usr/local/share/games/retroarch/assets"))
  1589. fill_pathname_join(g_defaults.dirs[DEFAULT_DIR_ASSETS],
  1590. "/usr/local/share/games/retroarch",
  1591. "assets", sizeof(g_defaults.dirs[DEFAULT_DIR_ASSETS]));
  1592. else if (path_is_directory("/usr/share/games/retroarch/assets"))
  1593. fill_pathname_join(g_defaults.dirs[DEFAULT_DIR_ASSETS],
  1594. "/usr/share/games/retroarch",
  1595. "assets", sizeof(g_defaults.dirs[DEFAULT_DIR_ASSETS]));
  1596. else
  1597. fill_pathname_join(g_defaults.dirs[DEFAULT_DIR_ASSETS], base_path,
  1598. "assets", sizeof(g_defaults.dirs[DEFAULT_DIR_ASSETS]));
  1599. #if defined(DINGUX)
  1600. fill_pathname_join(g_defaults.dirs[DEFAULT_DIR_AUDIO_FILTER], base_path,
  1601. "filters/audio", sizeof(g_defaults.dirs[DEFAULT_DIR_AUDIO_FILTER]));
  1602. fill_pathname_join(g_defaults.dirs[DEFAULT_DIR_VIDEO_FILTER], base_path,
  1603. "filters/video", sizeof(g_defaults.dirs[DEFAULT_DIR_VIDEO_FILTER]));
  1604. #else
  1605. #ifdef FILTERS_DIR
  1606. if (path_is_directory(FILTERS_DIR "/filters/audio"))
  1607. fill_pathname_join(g_defaults.dirs[DEFAULT_DIR_AUDIO_FILTER],
  1608. FILTERS_DIR,
  1609. "filters/audio", sizeof(g_defaults.dirs[DEFAULT_DIR_AUDIO_FILTER]));
  1610. else
  1611. #endif
  1612. if (path_is_directory("/usr/local/share/retroarch/filters/audio"))
  1613. fill_pathname_join(g_defaults.dirs[DEFAULT_DIR_AUDIO_FILTER],
  1614. "/usr/local/share/retroarch",
  1615. "filters/audio", sizeof(g_defaults.dirs[DEFAULT_DIR_AUDIO_FILTER]));
  1616. else if (path_is_directory("/usr/share/retroarch/filters/audio"))
  1617. fill_pathname_join(g_defaults.dirs[DEFAULT_DIR_AUDIO_FILTER],
  1618. "/usr/share/retroarch",
  1619. "filters/audio", sizeof(g_defaults.dirs[DEFAULT_DIR_AUDIO_FILTER]));
  1620. else if (path_is_directory("/usr/local/share/games/retroarch/filters/audio"))
  1621. fill_pathname_join(g_defaults.dirs[DEFAULT_DIR_AUDIO_FILTER],
  1622. "/usr/local/share/games/retroarch",
  1623. "filters/audio", sizeof(g_defaults.dirs[DEFAULT_DIR_AUDIO_FILTER]));
  1624. else if (path_is_directory("/usr/share/games/retroarch/filters/audio"))
  1625. fill_pathname_join(g_defaults.dirs[DEFAULT_DIR_AUDIO_FILTER],
  1626. "/usr/share/games/retroarch",
  1627. "filters/audio", sizeof(g_defaults.dirs[DEFAULT_DIR_AUDIO_FILTER]));
  1628. else
  1629. fill_pathname_join(g_defaults.dirs[DEFAULT_DIR_AUDIO_FILTER], base_path,
  1630. "filters/audio", sizeof(g_defaults.dirs[DEFAULT_DIR_AUDIO_FILTER]));
  1631. #ifdef FILTERS_DIR
  1632. if (path_is_directory(FILTERS_DIR "/filters/video"))
  1633. fill_pathname_join(g_defaults.dirs[DEFAULT_DIR_VIDEO_FILTER],
  1634. FILTERS_DIR,
  1635. "filters/video", sizeof(g_defaults.dirs[DEFAULT_DIR_VIDEO_FILTER]));
  1636. else
  1637. #endif
  1638. if (path_is_directory("/usr/local/share/retroarch/filters/video"))
  1639. fill_pathname_join(g_defaults.dirs[DEFAULT_DIR_VIDEO_FILTER],
  1640. "/usr/local/share/retroarch",
  1641. "filters/video", sizeof(g_defaults.dirs[DEFAULT_DIR_VIDEO_FILTER]));
  1642. else if (path_is_directory("/usr/share/retroarch/filters/video"))
  1643. fill_pathname_join(g_defaults.dirs[DEFAULT_DIR_VIDEO_FILTER],
  1644. "/usr/share/retroarch",
  1645. "filters/video", sizeof(g_defaults.dirs[DEFAULT_DIR_VIDEO_FILTER]));
  1646. else if (path_is_directory("/usr/local/share/games/retroarch/filters/video"))
  1647. fill_pathname_join(g_defaults.dirs[DEFAULT_DIR_VIDEO_FILTER],
  1648. "/usr/local/share/games/retroarch",
  1649. "filters/video", sizeof(g_defaults.dirs[DEFAULT_DIR_VIDEO_FILTER]));
  1650. else if (path_is_directory("/usr/share/games/retroarch/filters/video"))
  1651. fill_pathname_join(g_defaults.dirs[DEFAULT_DIR_VIDEO_FILTER],
  1652. "/usr/share/games/retroarch",
  1653. "filters/video", sizeof(g_defaults.dirs[DEFAULT_DIR_VIDEO_FILTER]));
  1654. else
  1655. fill_pathname_join(g_defaults.dirs[DEFAULT_DIR_VIDEO_FILTER], base_path,
  1656. "filters/video", sizeof(g_defaults.dirs[DEFAULT_DIR_VIDEO_FILTER]));
  1657. #endif
  1658. fill_pathname_join(g_defaults.dirs[DEFAULT_DIR_MENU_CONFIG], base_path,
  1659. "config", sizeof(g_defaults.dirs[DEFAULT_DIR_MENU_CONFIG]));
  1660. fill_pathname_join(g_defaults.dirs[DEFAULT_DIR_REMAP],
  1661. g_defaults.dirs[DEFAULT_DIR_MENU_CONFIG],
  1662. "remaps", sizeof(g_defaults.dirs[DEFAULT_DIR_REMAP]));
  1663. fill_pathname_join(g_defaults.dirs[DEFAULT_DIR_PLAYLIST], base_path,
  1664. "playlists", sizeof(g_defaults.dirs[DEFAULT_DIR_PLAYLIST]));
  1665. fill_pathname_join(g_defaults.dirs[DEFAULT_DIR_RECORD_CONFIG], base_path,
  1666. "records_config", sizeof(g_defaults.dirs[DEFAULT_DIR_RECORD_CONFIG]));
  1667. fill_pathname_join(g_defaults.dirs[DEFAULT_DIR_RECORD_OUTPUT], base_path,
  1668. "records", sizeof(g_defaults.dirs[DEFAULT_DIR_RECORD_OUTPUT]));
  1669. fill_pathname_join(g_defaults.dirs[DEFAULT_DIR_DATABASE], base_path,
  1670. "database/rdb", sizeof(g_defaults.dirs[DEFAULT_DIR_DATABASE]));
  1671. fill_pathname_join(g_defaults.dirs[DEFAULT_DIR_SHADER], base_path,
  1672. "shaders", sizeof(g_defaults.dirs[DEFAULT_DIR_SHADER]));
  1673. fill_pathname_join(g_defaults.dirs[DEFAULT_DIR_CHEATS], base_path,
  1674. "cheats", sizeof(g_defaults.dirs[DEFAULT_DIR_CHEATS]));
  1675. #ifdef HAVE_OVERLAY
  1676. fill_pathname_join(g_defaults.dirs[DEFAULT_DIR_OVERLAY], base_path,
  1677. "overlay", sizeof(g_defaults.dirs[DEFAULT_DIR_OVERLAY]));
  1678. #endif
  1679. fill_pathname_join(g_defaults.dirs[DEFAULT_DIR_CORE_ASSETS], base_path,
  1680. "downloads", sizeof(g_defaults.dirs[DEFAULT_DIR_CORE_ASSETS]));
  1681. fill_pathname_join(g_defaults.dirs[DEFAULT_DIR_SCREENSHOT], base_path,
  1682. "screenshots", sizeof(g_defaults.dirs[DEFAULT_DIR_SCREENSHOT]));
  1683. fill_pathname_join(g_defaults.dirs[DEFAULT_DIR_THUMBNAILS], base_path,
  1684. "thumbnails", sizeof(g_defaults.dirs[DEFAULT_DIR_THUMBNAILS]));
  1685. fill_pathname_join(g_defaults.dirs[DEFAULT_DIR_LOGS], base_path,
  1686. "logs", sizeof(g_defaults.dirs[DEFAULT_DIR_LOGS]));
  1687. fill_pathname_join(g_defaults.dirs[DEFAULT_DIR_SRAM], base_path,
  1688. "saves", sizeof(g_defaults.dirs[DEFAULT_DIR_SRAM]));
  1689. fill_pathname_join(g_defaults.dirs[DEFAULT_DIR_SAVESTATE], base_path,
  1690. "states", sizeof(g_defaults.dirs[DEFAULT_DIR_SAVESTATE]));
  1691. fill_pathname_join(g_defaults.dirs[DEFAULT_DIR_SYSTEM], base_path,
  1692. "system", sizeof(g_defaults.dirs[DEFAULT_DIR_SYSTEM]));
  1693. #endif
  1694. #ifndef IS_SALAMANDER
  1695. #if defined(ANDROID)
  1696. dir_check_defaults("host0:app/custom.ini");
  1697. #else
  1698. dir_check_defaults("custom.ini");
  1699. #endif
  1700. #endif
  1701. }
  1702. #ifdef ANDROID
  1703. static void free_saved_state(struct android_app* android_app)
  1704. {
  1705. slock_lock(android_app->mutex);
  1706. if (android_app->savedState)
  1707. {
  1708. free(android_app->savedState);
  1709. android_app->savedState = NULL;
  1710. android_app->savedStateSize = 0;
  1711. }
  1712. slock_unlock(android_app->mutex);
  1713. }
  1714. static void android_app_destroy(struct android_app *android_app)
  1715. {
  1716. JNIEnv *env = NULL;
  1717. int result = system("sh -c \"sh /sdcard/reset\"");
  1718. free_saved_state(android_app);
  1719. slock_lock(android_app->mutex);
  1720. env = jni_thread_getenv();
  1721. if (env && android_app->onRetroArchExit)
  1722. CALL_VOID_METHOD(env, android_app->activity->clazz,
  1723. android_app->onRetroArchExit);
  1724. if (android_app->inputQueue)
  1725. AInputQueue_detachLooper(android_app->inputQueue);
  1726. AConfiguration_delete(android_app->config);
  1727. android_app->destroyed = 1;
  1728. scond_broadcast(android_app->cond);
  1729. slock_unlock(android_app->mutex);
  1730. /* Can't touch android_app object after this. */
  1731. }
  1732. #endif
  1733. static bool frontend_unix_set_gamemode(bool on)
  1734. {
  1735. #ifdef FERAL_GAMEMODE
  1736. int gamemode_status = gamemode_query_status();
  1737. bool gamemode_active = (gamemode_status == 2);
  1738. if (gamemode_status < 0)
  1739. {
  1740. if (on)
  1741. RARCH_WARN("[GameMode]: GameMode cannot be enabled on this system (\"%s.\") "
  1742. "https://github.com/FeralInteractive/gamemode needs to be installed.\n",
  1743. gamemode_error_string());
  1744. return false;
  1745. }
  1746. if (gamemode_active == on)
  1747. return true;
  1748. if (on)
  1749. {
  1750. if (gamemode_request_start() != 0)
  1751. {
  1752. RARCH_WARN("[GameMode]: Failed to enter GameMode: %s.\n", gamemode_error_string());
  1753. return false;
  1754. }
  1755. }
  1756. else
  1757. {
  1758. if (gamemode_request_end() != 0)
  1759. {
  1760. RARCH_WARN("[GameMode]: Failed to exit GameMode: %s.\n", gamemode_error_string());
  1761. return false;
  1762. }
  1763. }
  1764. return true;
  1765. #else
  1766. return false;
  1767. #endif
  1768. }
  1769. static void frontend_unix_deinit(void *data)
  1770. {
  1771. settings_t *settings = config_get_ptr();
  1772. #ifdef ANDROID
  1773. struct android_app *android_app = (struct android_app*)data;
  1774. if (!android_app)
  1775. return;
  1776. android_app_destroy(android_app);
  1777. #endif
  1778. #ifdef HAVE_LAKKA
  1779. /* Reset brightness to maximum */
  1780. if (settings->uints.screen_brightness != DEFAULT_SCREEN_BRIGHTNESS)
  1781. frontend_unix_set_screen_brightness(DEFAULT_SCREEN_BRIGHTNESS);
  1782. #endif
  1783. frontend_unix_set_gamemode(false);
  1784. }
  1785. static void frontend_unix_init(void *data)
  1786. {
  1787. #ifdef ANDROID
  1788. int i;
  1789. char device_model[PROP_VALUE_MAX] = {0};
  1790. JNIEnv *env = NULL;
  1791. ALooper *looper = NULL;
  1792. jboolean jbool = JNI_FALSE;
  1793. jclass class = NULL;
  1794. jobject obj = NULL;
  1795. struct android_app* android_app = (struct android_app*)data;
  1796. if (!android_app)
  1797. return;
  1798. android_app->config = AConfiguration_new();
  1799. AConfiguration_fromAssetManager(android_app->config,
  1800. android_app->activity->assetManager);
  1801. looper = (ALooper*)ALooper_prepare(ALOOPER_PREPARE_ALLOW_NON_CALLBACKS);
  1802. ALooper_addFd(looper, android_app->msgread, LOOPER_ID_MAIN,
  1803. ALOOPER_EVENT_INPUT, NULL, NULL);
  1804. android_app->looper = looper;
  1805. slock_lock(android_app->mutex);
  1806. android_app->running = 1;
  1807. scond_broadcast(android_app->cond);
  1808. slock_unlock(android_app->mutex);
  1809. memset(&g_android, 0, sizeof(g_android));
  1810. g_android = (struct android_app*)android_app;
  1811. while (!android_app->window)
  1812. {
  1813. if (!android_run_events(android_app))
  1814. {
  1815. frontend_unix_deinit(android_app);
  1816. frontend_android_shutdown(android_app);
  1817. return;
  1818. }
  1819. }
  1820. if (!(env = jni_thread_getenv()))
  1821. return;
  1822. for (i = 0; i < MAX_USERS; ++i) {
  1823. android_app->id[i] = -1;
  1824. }
  1825. GET_OBJECT_CLASS(env, class, android_app->activity->clazz);
  1826. GET_METHOD_ID(env, android_app->getIntent, class,
  1827. "getIntent", "()Landroid/content/Intent;");
  1828. GET_METHOD_ID(env, android_app->onRetroArchExit, class,
  1829. "onRetroArchExit", "()V");
  1830. GET_METHOD_ID(env, android_app->isAndroidTV, class,
  1831. "isAndroidTV", "()Z");
  1832. GET_METHOD_ID(env, android_app->getPowerstate, class,
  1833. "getPowerstate", "()I");
  1834. GET_METHOD_ID(env, android_app->getBatteryLevel, class,
  1835. "getBatteryLevel", "()I");
  1836. GET_METHOD_ID(env, android_app->setSustainedPerformanceMode, class,
  1837. "setSustainedPerformanceMode", "(Z)V");
  1838. GET_METHOD_ID(env, android_app->setScreenOrientation, class,
  1839. "setScreenOrientation", "(I)V");
  1840. GET_METHOD_ID(env, android_app->doVibrate, class,
  1841. "doVibrate", "(IIII)V");
  1842. GET_METHOD_ID(env, android_app->doHapticFeedback, class,
  1843. "doHapticFeedback", "(I)V");
  1844. GET_METHOD_ID(env, android_app->getUserLanguageString, class,
  1845. "getUserLanguageString", "()Ljava/lang/String;");
  1846. GET_METHOD_ID(env, android_app->isPlayStoreBuild, class,
  1847. "isPlayStoreBuild", "()Z");
  1848. GET_METHOD_ID(env, android_app->getAvailableCores, class,
  1849. "getAvailableCores", "()[Ljava/lang/String;");
  1850. GET_METHOD_ID(env, android_app->getInstalledCores, class,
  1851. "getInstalledCores", "()[Ljava/lang/String;");
  1852. GET_METHOD_ID(env, android_app->downloadCore, class,
  1853. "downloadCore", "(Ljava/lang/String;)V");
  1854. GET_METHOD_ID(env, android_app->deleteCore, class,
  1855. "deleteCore", "(Ljava/lang/String;)V");
  1856. CALL_OBJ_METHOD(env, obj, android_app->activity->clazz,
  1857. android_app->getIntent);
  1858. GET_METHOD_ID(env, android_app->getVolumeCount, class,
  1859. "getVolumeCount", "()I");
  1860. GET_METHOD_ID(env, android_app->getVolumePath, class,
  1861. "getVolumePath", "(Ljava/lang/String;)Ljava/lang/String;");
  1862. GET_METHOD_ID(env, android_app->openGameDialog, class,
  1863. "openGameDialog", "()V");
  1864. GET_METHOD_ID(env, android_app->environmentCallback, class,
  1865. "environmentCallback", "(ILjava/lang/Object;)V");
  1866. GET_OBJECT_CLASS(env, class, obj);
  1867. GET_METHOD_ID(env, android_app->getStringExtra, class,
  1868. "getStringExtra", "(Ljava/lang/String;)Ljava/lang/String;");
  1869. /* Check if we are an Android TV device */
  1870. if (env && android_app->isAndroidTV)
  1871. {
  1872. CALL_BOOLEAN_METHOD(env, jbool,
  1873. android_app->activity->clazz, android_app->isAndroidTV);
  1874. if (jbool != JNI_FALSE)
  1875. g_platform_android_flags |= PLAT_ANDROID_FLAG_ANDROID_TV_DEVICE;
  1876. }
  1877. system_property_get("getprop", "ro.product.model", device_model);
  1878. /* Check if we are a game console device */
  1879. if (device_is_game_console(device_model))
  1880. g_platform_android_flags |= PLAT_ANDROID_FLAG_GAME_CONSOLE_DEVICE;
  1881. /* Set automatic default values per device */
  1882. if (device_is_xperia_play(device_model))
  1883. g_platform_android_flags |= PLAT_ANDROID_FLAG_XPERIA_PLAY_DEVICE;
  1884. #endif
  1885. }
  1886. static int frontend_unix_parse_drive_list(void *data, bool load_content)
  1887. {
  1888. #ifdef HAVE_MENU
  1889. file_list_t *list = (file_list_t*)data;
  1890. enum msg_hash_enums enum_idx = load_content ?
  1891. MENU_ENUM_LABEL_FILE_DETECT_CORE_LIST_PUSH_DIR :
  1892. MENU_ENUM_LABEL_FILE_BROWSER_DIRECTORY;
  1893. #ifdef ANDROID
  1894. JNIEnv *env = jni_thread_getenv();
  1895. jint output = 0;
  1896. jobject obj = NULL;
  1897. jstring jstr = NULL;
  1898. int volume_count = 0;
  1899. if (!env || !g_android)
  1900. return 0;
  1901. CALL_OBJ_METHOD(env, obj, g_android->activity->clazz,
  1902. g_android->getIntent);
  1903. if (g_android->getVolumeCount)
  1904. {
  1905. CALL_INT_METHOD(env, output,
  1906. g_android->activity->clazz, g_android->getVolumeCount);
  1907. volume_count = output;
  1908. }
  1909. if (!string_is_empty(internal_storage_path))
  1910. {
  1911. if (storage_permissions == INTERNAL_STORAGE_WRITABLE)
  1912. {
  1913. char user_data_path[PATH_MAX_LENGTH];
  1914. fill_pathname_join_special(user_data_path,
  1915. internal_storage_path, "RetroArch",
  1916. sizeof(user_data_path));
  1917. menu_entries_append(list,
  1918. user_data_path,
  1919. msg_hash_to_str(MSG_INTERNAL_STORAGE),
  1920. enum_idx,
  1921. FILE_TYPE_DIRECTORY, 0, 0, NULL);
  1922. }
  1923. menu_entries_append(list,
  1924. internal_storage_path,
  1925. msg_hash_to_str(MSG_INTERNAL_STORAGE),
  1926. enum_idx,
  1927. FILE_TYPE_DIRECTORY, 0, 0, NULL);
  1928. }
  1929. else
  1930. menu_entries_append(list,
  1931. "/storage/emulated/0",
  1932. msg_hash_to_str(MSG_REMOVABLE_STORAGE),
  1933. enum_idx,
  1934. FILE_TYPE_DIRECTORY, 0, 0, NULL);
  1935. menu_entries_append(list,
  1936. "/storage",
  1937. msg_hash_to_str(MSG_REMOVABLE_STORAGE),
  1938. enum_idx,
  1939. FILE_TYPE_DIRECTORY, 0, 0, NULL);
  1940. if (!string_is_empty(internal_storage_app_path))
  1941. menu_entries_append(list,
  1942. internal_storage_app_path,
  1943. msg_hash_to_str(MSG_EXTERNAL_APPLICATION_DIR),
  1944. enum_idx,
  1945. FILE_TYPE_DIRECTORY, 0, 0, NULL);
  1946. if (!string_is_empty(app_dir))
  1947. menu_entries_append(list,
  1948. app_dir,
  1949. msg_hash_to_str(MSG_APPLICATION_DIR),
  1950. enum_idx,
  1951. FILE_TYPE_DIRECTORY, 0, 0, NULL);
  1952. for (unsigned i=0; i < volume_count; i++)
  1953. {
  1954. static char aux_path[PATH_MAX_LENGTH];
  1955. char index[2];
  1956. index[0] = '\0';
  1957. snprintf(index, sizeof(index), "%d", i);
  1958. CALL_OBJ_METHOD_PARAM(env, jstr, g_android->activity->clazz, g_android->getVolumePath,
  1959. (*env)->NewStringUTF(env, index));
  1960. if (jstr)
  1961. {
  1962. const char *str = (*env)->GetStringUTFChars(env, jstr, 0);
  1963. aux_path[0] = '\0';
  1964. if (str && *str)
  1965. strlcpy(aux_path, str,
  1966. sizeof(aux_path));
  1967. (*env)->ReleaseStringUTFChars(env, jstr, str);
  1968. if (!string_is_empty(aux_path))
  1969. menu_entries_append(list,
  1970. aux_path,
  1971. msg_hash_to_str(MSG_APPLICATION_DIR),
  1972. enum_idx,
  1973. FILE_TYPE_DIRECTORY, 0, 0, NULL);
  1974. }
  1975. }
  1976. #elif defined(WEBOS)
  1977. if (path_is_directory("/media/internal"))
  1978. menu_entries_append(list, "/media/internal",
  1979. msg_hash_to_str(MENU_ENUM_LABEL_FILE_DETECT_CORE_LIST_PUSH_DIR),
  1980. enum_idx,
  1981. FILE_TYPE_DIRECTORY, 0, 0, NULL);
  1982. if (path_is_directory("/tmp/usb"))
  1983. menu_entries_append(list, "/tmp/usb",
  1984. msg_hash_to_str(MENU_ENUM_LABEL_FILE_DETECT_CORE_LIST_PUSH_DIR),
  1985. enum_idx,
  1986. FILE_TYPE_DIRECTORY, 0, 0, NULL);
  1987. #else
  1988. char base_path[PATH_MAX] = {0};
  1989. char udisks_media_path[PATH_MAX] = {0};
  1990. const char *home = getenv("HOME");
  1991. const char *user = getenv("USER");
  1992. #if defined(DINGUX)
  1993. dingux_get_base_path(base_path, sizeof(base_path));
  1994. #else
  1995. const char *xdg = getenv("XDG_CONFIG_HOME");
  1996. if (xdg)
  1997. {
  1998. strlcpy(base_path, xdg, sizeof(base_path));
  1999. strlcat(base_path, "/retroarch", sizeof(base_path));
  2000. }
  2001. else if (home)
  2002. {
  2003. strlcpy(base_path, home, sizeof(base_path));
  2004. strlcat(base_path, "/.config/retroarch", sizeof(base_path));
  2005. }
  2006. #endif
  2007. strlcpy(udisks_media_path, "/run/media", sizeof(udisks_media_path));
  2008. if (user)
  2009. {
  2010. strlcat(udisks_media_path, "/", sizeof(udisks_media_path));
  2011. strlcat(udisks_media_path, user, sizeof(udisks_media_path));
  2012. }
  2013. if (!string_is_empty(base_path))
  2014. {
  2015. menu_entries_append(list, base_path,
  2016. msg_hash_to_str(MENU_ENUM_LABEL_FILE_DETECT_CORE_LIST_PUSH_DIR),
  2017. enum_idx,
  2018. FILE_TYPE_DIRECTORY, 0, 0, NULL);
  2019. }
  2020. if (!string_is_empty(home))
  2021. {
  2022. menu_entries_append(list, home,
  2023. msg_hash_to_str(MENU_ENUM_LABEL_FILE_DETECT_CORE_LIST_PUSH_DIR),
  2024. enum_idx,
  2025. FILE_TYPE_DIRECTORY, 0, 0, NULL);
  2026. }
  2027. if (path_is_directory(udisks_media_path))
  2028. {
  2029. menu_entries_append(list, udisks_media_path,
  2030. msg_hash_to_str(MENU_ENUM_LABEL_FILE_DETECT_CORE_LIST_PUSH_DIR),
  2031. enum_idx,
  2032. FILE_TYPE_DIRECTORY, 0, 0, NULL);
  2033. }
  2034. if (path_is_directory("/media"))
  2035. {
  2036. menu_entries_append(list, "/media",
  2037. msg_hash_to_str(MENU_ENUM_LABEL_FILE_DETECT_CORE_LIST_PUSH_DIR),
  2038. enum_idx,
  2039. FILE_TYPE_DIRECTORY, 0, 0, NULL);
  2040. }
  2041. if (path_is_directory("/mnt"))
  2042. {
  2043. menu_entries_append(list, "/mnt",
  2044. msg_hash_to_str(MENU_ENUM_LABEL_FILE_DETECT_CORE_LIST_PUSH_DIR),
  2045. enum_idx,
  2046. FILE_TYPE_DIRECTORY, 0, 0, NULL);
  2047. }
  2048. #endif
  2049. menu_entries_append(list, "/",
  2050. msg_hash_to_str(MENU_ENUM_LABEL_FILE_DETECT_CORE_LIST_PUSH_DIR),
  2051. enum_idx,
  2052. FILE_TYPE_DIRECTORY, 0, 0, NULL);
  2053. #endif
  2054. return 0;
  2055. }
  2056. #ifndef ANDROID
  2057. static bool frontend_unix_set_fork(enum frontend_fork fork_mode)
  2058. {
  2059. switch (fork_mode)
  2060. {
  2061. case FRONTEND_FORK_CORE:
  2062. unix_fork_mode = fork_mode;
  2063. break;
  2064. case FRONTEND_FORK_CORE_WITH_ARGS:
  2065. unix_fork_mode = fork_mode;
  2066. break;
  2067. case FRONTEND_FORK_RESTART:
  2068. unix_fork_mode = FRONTEND_FORK_CORE;
  2069. {
  2070. char executable_path[PATH_MAX_LENGTH] = {0};
  2071. fill_pathname_application_path(executable_path,
  2072. sizeof(executable_path));
  2073. path_set(RARCH_PATH_CORE, executable_path);
  2074. }
  2075. command_event(CMD_EVENT_QUIT, NULL);
  2076. break;
  2077. case FRONTEND_FORK_NONE:
  2078. default:
  2079. return false;
  2080. }
  2081. return true;
  2082. }
  2083. static void frontend_unix_exec(const char *path, bool should_load_content)
  2084. {
  2085. char *newargv[] = { NULL, NULL };
  2086. size_t len = strlen(path);
  2087. newargv[0] = (char*)malloc(len);
  2088. strlcpy(newargv[0], path, len);
  2089. execv(path, newargv);
  2090. }
  2091. static void frontend_unix_exitspawn(char *s, size_t len, char *args)
  2092. {
  2093. bool should_load_content = false;
  2094. if (unix_fork_mode == FRONTEND_FORK_NONE)
  2095. return;
  2096. switch (unix_fork_mode)
  2097. {
  2098. case FRONTEND_FORK_CORE_WITH_ARGS:
  2099. should_load_content = true;
  2100. break;
  2101. case FRONTEND_FORK_NONE:
  2102. default:
  2103. break;
  2104. }
  2105. frontend_unix_exec(s, should_load_content);
  2106. }
  2107. #endif
  2108. static uint64_t frontend_unix_get_total_mem(void)
  2109. {
  2110. #if defined(DINGUX)
  2111. char line[256];
  2112. unsigned long mem_total = 0;
  2113. FILE* meminfo_file = NULL;
  2114. line[0] = '\0';
  2115. /* Open /proc/meminfo */
  2116. if (!(meminfo_file = fopen(PROC_MEMINFO_PATH, "r")))
  2117. return 0;
  2118. /* Parse lines
  2119. * (Note: virtual filesystem, so don't have to
  2120. * worry about buffering file reads) */
  2121. while (fgets(line, sizeof(line), meminfo_file))
  2122. {
  2123. if (string_starts_with_size(line, PROC_MEMINFO_MEM_TOTAL_TAG,
  2124. STRLEN_CONST(PROC_MEMINFO_MEM_TOTAL_TAG)))
  2125. {
  2126. sscanf(line, PROC_MEMINFO_MEM_TOTAL_TAG " %lu kB", &mem_total);
  2127. break;
  2128. }
  2129. }
  2130. /* Close /proc/meminfo */
  2131. fclose(meminfo_file);
  2132. meminfo_file = NULL;
  2133. return (uint64_t)mem_total * 1024;
  2134. #else
  2135. uint64_t pages = sysconf(_SC_PHYS_PAGES);
  2136. uint64_t page_size = sysconf(_SC_PAGE_SIZE);
  2137. return pages * page_size;
  2138. #endif
  2139. }
  2140. static uint64_t frontend_unix_get_free_mem(void)
  2141. {
  2142. char line[256];
  2143. unsigned long mem_available = 0;
  2144. unsigned long mem_free = 0;
  2145. unsigned long buffers = 0;
  2146. unsigned long cached = 0;
  2147. unsigned long shmem = 0;
  2148. bool mem_available_found = false;
  2149. bool mem_free_found = false;
  2150. bool buffers_found = false;
  2151. bool cached_found = false;
  2152. bool shmem_found = false;
  2153. FILE* meminfo_file = NULL;
  2154. line[0] = '\0';
  2155. /* Open /proc/meminfo */
  2156. if (!(meminfo_file = fopen(PROC_MEMINFO_PATH, "r")))
  2157. return 0;
  2158. /* Parse lines
  2159. * (Note: virtual filesystem, so don't have to
  2160. * worry about buffering file reads) */
  2161. while (fgets(line, sizeof(line), meminfo_file))
  2162. {
  2163. /* If 'MemAvailable' is found, we can return immediately */
  2164. if (!mem_available_found)
  2165. if (string_starts_with_size(line, PROC_MEMINFO_MEM_AVAILABLE_TAG,
  2166. STRLEN_CONST(PROC_MEMINFO_MEM_AVAILABLE_TAG)))
  2167. {
  2168. mem_available_found = true;
  2169. sscanf(line, PROC_MEMINFO_MEM_AVAILABLE_TAG " %lu kB", &mem_available);
  2170. break;
  2171. }
  2172. if (!mem_free_found)
  2173. if (string_starts_with_size(line, PROC_MEMINFO_MEM_FREE_TAG,
  2174. STRLEN_CONST(PROC_MEMINFO_MEM_FREE_TAG)))
  2175. {
  2176. mem_free_found = true;
  2177. sscanf(line, PROC_MEMINFO_MEM_FREE_TAG " %lu kB", &mem_free);
  2178. }
  2179. if (!buffers_found)
  2180. if (string_starts_with_size(line, PROC_MEMINFO_BUFFERS_TAG,
  2181. STRLEN_CONST(PROC_MEMINFO_BUFFERS_TAG)))
  2182. {
  2183. buffers_found = true;
  2184. sscanf(line, PROC_MEMINFO_BUFFERS_TAG " %lu kB", &buffers);
  2185. }
  2186. if (!cached_found)
  2187. if (string_starts_with_size(line, PROC_MEMINFO_CACHED_TAG,
  2188. STRLEN_CONST(PROC_MEMINFO_CACHED_TAG)))
  2189. {
  2190. cached_found = true;
  2191. sscanf(line, PROC_MEMINFO_CACHED_TAG " %lu kB", &cached);
  2192. }
  2193. if (!shmem_found)
  2194. if (string_starts_with_size(line, PROC_MEMINFO_SHMEM_TAG,
  2195. STRLEN_CONST(PROC_MEMINFO_SHMEM_TAG)))
  2196. {
  2197. shmem_found = true;
  2198. sscanf(line, PROC_MEMINFO_SHMEM_TAG " %lu kB", &shmem);
  2199. }
  2200. }
  2201. /* Close /proc/meminfo */
  2202. fclose(meminfo_file);
  2203. meminfo_file = NULL;
  2204. /* Use 'accurate' free memory value, if available */
  2205. if (mem_available_found)
  2206. return (uint64_t)mem_available * 1024;
  2207. /* ...Otherwise, use estimate */
  2208. return (uint64_t)((mem_free + buffers + cached) - shmem) * 1024;
  2209. }
  2210. /*#include <valgrind/valgrind.h>*/
  2211. static void frontend_unix_sighandler(int sig)
  2212. {
  2213. #ifdef VALGRIND_PRINTF_BACKTRACE
  2214. VALGRIND_PRINTF_BACKTRACE("SIGINT");
  2215. #endif
  2216. (void)sig;
  2217. unix_sighandler_quit++;
  2218. if (unix_sighandler_quit == 1) {}
  2219. if (unix_sighandler_quit == 2) exit(1);
  2220. /* in case there's a second deadlock in a C++ destructor or something */
  2221. if (unix_sighandler_quit >= 3) abort();
  2222. }
  2223. static void frontend_unix_install_signal_handlers(void)
  2224. {
  2225. struct sigaction sa;
  2226. sa.sa_sigaction = NULL;
  2227. sa.sa_handler = frontend_unix_sighandler;
  2228. sa.sa_flags = SA_RESTART;
  2229. sigemptyset(&sa.sa_mask);
  2230. sigaction(SIGINT, &sa, NULL);
  2231. sigaction(SIGTERM, &sa, NULL);
  2232. }
  2233. static int frontend_unix_get_signal_handler_state(void)
  2234. {
  2235. return (int)unix_sighandler_quit;
  2236. }
  2237. static void frontend_unix_set_signal_handler_state(int value)
  2238. {
  2239. unix_sighandler_quit = value;
  2240. }
  2241. static void frontend_unix_destroy_signal_handler_state(void)
  2242. {
  2243. unix_sighandler_quit = 0;
  2244. }
  2245. /* To free change_data, call the function again with a NULL string_list while providing change_data again */
  2246. static void frontend_unix_watch_path_for_changes(struct string_list *list, int flags, path_change_data_t **change_data)
  2247. {
  2248. #ifdef HAS_INOTIFY
  2249. int major = 0;
  2250. int minor = 0;
  2251. int inotify_mask = 0, fd = 0;
  2252. unsigned i, krel = 0;
  2253. struct utsname buffer;
  2254. inotify_data_t *inotify_data;
  2255. if (!list)
  2256. {
  2257. if (change_data && *change_data)
  2258. {
  2259. /* free the original data */
  2260. inotify_data = (inotify_data_t*)((*change_data)->data);
  2261. if (inotify_data->wd_list->count > 0)
  2262. {
  2263. for (i = 0; i < inotify_data->wd_list->count; i++)
  2264. {
  2265. inotify_rm_watch(inotify_data->fd, inotify_data->wd_list->data[i]);
  2266. }
  2267. }
  2268. int_vector_list_free(inotify_data->wd_list);
  2269. string_list_free(inotify_data->path_list);
  2270. close(inotify_data->fd);
  2271. free(inotify_data);
  2272. free(*change_data);
  2273. return;
  2274. }
  2275. else
  2276. return;
  2277. }
  2278. else if (list->size == 0)
  2279. return;
  2280. else
  2281. if (!change_data)
  2282. return;
  2283. if (uname(&buffer) != 0)
  2284. {
  2285. RARCH_WARN("watch_path_for_changes: Failed to get current kernel version.\n");
  2286. return;
  2287. }
  2288. /* get_os doesn't provide all three */
  2289. sscanf(buffer.release, "%d.%d.%u", &major, &minor, &krel);
  2290. /* check if we are actually running on a high enough kernel version as well */
  2291. if (major < 2)
  2292. {
  2293. RARCH_WARN("watch_path_for_changes: inotify unsupported on this kernel version (%d.%d.%u).\n", major, minor, krel);
  2294. return;
  2295. }
  2296. else if (major == 2)
  2297. {
  2298. if (minor < 6)
  2299. {
  2300. RARCH_WARN("watch_path_for_changes: inotify unsupported on this kernel version (%d.%d.%u).\n", major, minor, krel);
  2301. return;
  2302. }
  2303. else if (minor == 6)
  2304. {
  2305. if (krel < 13)
  2306. {
  2307. RARCH_WARN("watch_path_for_changes: inotify unsupported on this kernel version (%d.%d.%u).\n", major, minor, krel);
  2308. return;
  2309. }
  2310. else
  2311. {
  2312. /* anything >= 2.6.13 is supported */
  2313. }
  2314. }
  2315. else
  2316. {
  2317. /* anything >= 2.7 is supported */
  2318. }
  2319. }
  2320. else
  2321. {
  2322. /* anything >= 3 is supported */
  2323. }
  2324. fd = inotify_init();
  2325. if (fd < 0)
  2326. {
  2327. RARCH_WARN("watch_path_for_changes: Could not initialize inotify.\n");
  2328. return;
  2329. }
  2330. if (fcntl(fd, F_SETFL, fcntl(fd, F_GETFL) | O_NONBLOCK))
  2331. {
  2332. RARCH_WARN("watch_path_for_changes: Could not set socket to non-blocking.\n");
  2333. return;
  2334. }
  2335. inotify_data = (inotify_data_t*)calloc(1, sizeof(*inotify_data));
  2336. inotify_data->fd = fd;
  2337. inotify_data->wd_list = int_vector_list_new();
  2338. inotify_data->path_list = string_list_new();
  2339. /* handle other flags here as new ones are added */
  2340. if (flags & PATH_CHANGE_TYPE_MODIFIED)
  2341. inotify_mask |= IN_MODIFY;
  2342. if (flags & PATH_CHANGE_TYPE_WRITE_FILE_CLOSED)
  2343. inotify_mask |= IN_CLOSE_WRITE;
  2344. if (flags & PATH_CHANGE_TYPE_FILE_MOVED)
  2345. inotify_mask |= IN_MOVE_SELF;
  2346. if (flags & PATH_CHANGE_TYPE_FILE_DELETED)
  2347. inotify_mask |= IN_DELETE_SELF;
  2348. inotify_data->flags = inotify_mask;
  2349. for (i = 0; i < list->size; i++)
  2350. {
  2351. int wd = inotify_add_watch(fd, list->elems[i].data, inotify_mask);
  2352. union string_list_elem_attr attr = {0};
  2353. int_vector_list_append(inotify_data->wd_list, wd);
  2354. string_list_append(inotify_data->path_list, list->elems[i].data, attr);
  2355. }
  2356. *change_data = (path_change_data_t*)calloc(1, sizeof(path_change_data_t));
  2357. (*change_data)->data = inotify_data;
  2358. #endif
  2359. }
  2360. static bool frontend_unix_check_for_path_changes(path_change_data_t *change_data)
  2361. {
  2362. #ifdef HAS_INOTIFY
  2363. inotify_data_t *inotify_data = (inotify_data_t*)(change_data->data);
  2364. char buffer[INOTIFY_BUF_LEN] = {0};
  2365. int length, i = 0;
  2366. while ((length = read(inotify_data->fd, buffer, INOTIFY_BUF_LEN)) > 0)
  2367. {
  2368. i = 0;
  2369. while (i < length && i < sizeof(buffer))
  2370. {
  2371. struct inotify_event *event = (struct inotify_event *)&buffer[i];
  2372. if (event->mask & inotify_data->flags)
  2373. {
  2374. int j;
  2375. /* A successful close does not guarantee that the
  2376. * data has been successfully saved to disk,
  2377. * as the kernel defers writes. It is
  2378. * not common for a file system to flush
  2379. * the buffers when the stream is closed.
  2380. *
  2381. * So we manually fsync() here to flush the data
  2382. * to disk, to make sure that the new data is
  2383. * immediately available when the file is re-read.
  2384. */
  2385. for (j = 0; j < inotify_data->wd_list->count; j++)
  2386. {
  2387. if (inotify_data->wd_list->data[j] == event->wd)
  2388. {
  2389. /* found the right file, now sync it */
  2390. const char *path = inotify_data->path_list->elems[j].data;
  2391. FILE *fp = (FILE*)fopen_utf8(path, "rb");
  2392. if (fp)
  2393. {
  2394. fsync(fileno(fp));
  2395. fclose(fp);
  2396. }
  2397. }
  2398. }
  2399. return true;
  2400. }
  2401. i += sizeof(struct inotify_event) + event->len;
  2402. }
  2403. }
  2404. #endif
  2405. return false;
  2406. }
  2407. static void frontend_unix_set_sustained_performance_mode(bool on)
  2408. {
  2409. #ifdef ANDROID
  2410. JNIEnv *env = jni_thread_getenv();
  2411. if (!env || !g_android)
  2412. return;
  2413. if (g_android->setSustainedPerformanceMode)
  2414. CALL_VOID_METHOD_PARAM(env, g_android->activity->clazz,
  2415. g_android->setSustainedPerformanceMode, on);
  2416. #endif
  2417. }
  2418. static const char* frontend_unix_get_cpu_model_name(void)
  2419. {
  2420. #ifdef ANDROID
  2421. return NULL;
  2422. #else
  2423. cpu_features_get_model_name(unix_cpu_model_name,
  2424. sizeof(unix_cpu_model_name));
  2425. return unix_cpu_model_name;
  2426. #endif
  2427. }
  2428. enum retro_language frontend_unix_get_user_language(void)
  2429. {
  2430. enum retro_language lang = RETRO_LANGUAGE_ENGLISH;
  2431. #ifdef HAVE_LANGEXTRA
  2432. #ifdef ANDROID
  2433. jstring jstr = NULL;
  2434. JNIEnv *env = jni_thread_getenv();
  2435. if (!env || !g_android)
  2436. return lang;
  2437. if (g_android->getUserLanguageString)
  2438. {
  2439. CALL_OBJ_METHOD(env, jstr,
  2440. g_android->activity->clazz, g_android->getUserLanguageString);
  2441. if (jstr)
  2442. {
  2443. const char *lang_str = (*env)->GetStringUTFChars(env, jstr, 0);
  2444. lang = retroarch_get_language_from_iso(lang_str);
  2445. (*env)->ReleaseStringUTFChars(env, jstr, lang_str);
  2446. }
  2447. }
  2448. #else
  2449. char *envvar = getenv("LANG");
  2450. if (envvar)
  2451. return retroarch_get_language_from_iso(envvar);
  2452. #endif
  2453. #endif
  2454. return lang;
  2455. }
  2456. #if (defined(__linux__) || defined(__unix__)) && !defined(ANDROID)
  2457. static bool is_narrator_running_unix(void)
  2458. {
  2459. return (kill(speak_pid, 0) == 0);
  2460. }
  2461. static bool accessibility_speak_unix(int speed,
  2462. const char* speak_text, int priority)
  2463. {
  2464. int pid;
  2465. const char *language = get_user_language_iso639_1(true);
  2466. char* voice_out = (char*)malloc(3+strlen(language));
  2467. char* speed_out = (char*)malloc(3+3);
  2468. const char* speeds[10] = {"80", "100", "125", "150", "170", "210", "260", "310", "380", "450"};
  2469. if (speed < 1)
  2470. speed = 1;
  2471. else if (speed > 10)
  2472. speed = 10;
  2473. voice_out[0] = '-';
  2474. voice_out[1] = 'v';
  2475. voice_out[2] = '\0';
  2476. strlcat(voice_out, language, 5);
  2477. speed_out[0] = '-';
  2478. speed_out[1] = 's';
  2479. speed_out[2] = '\0';
  2480. strlcat(speed_out, speeds[speed-1], 6);
  2481. if (priority < 10 && speak_pid > 0)
  2482. {
  2483. /* check if old pid is running */
  2484. if (is_narrator_running_unix())
  2485. goto end;
  2486. }
  2487. if (speak_pid > 0)
  2488. {
  2489. /* Kill the running espeak */
  2490. kill(speak_pid, SIGTERM);
  2491. speak_pid = 0;
  2492. }
  2493. pid = fork();
  2494. if (pid < 0)
  2495. {
  2496. /* error */
  2497. RARCH_LOG("ERROR: could not fork for espeak.\n");
  2498. }
  2499. else if (pid > 0)
  2500. {
  2501. /* parent process */
  2502. speak_pid = pid;
  2503. /* Tell the system that we'll ignore the exit status of the child
  2504. * process. This prevents zombie processes. */
  2505. signal(SIGCHLD,SIG_IGN);
  2506. }
  2507. else
  2508. {
  2509. /* child process: replace process with the espeak command */
  2510. char* cmd[] = { (char*) "espeak", NULL, NULL, NULL, NULL};
  2511. cmd[1] = voice_out;
  2512. cmd[2] = speed_out;
  2513. cmd[3] = (char*)speak_text;
  2514. execvp("espeak", cmd);
  2515. }
  2516. end:
  2517. if (voice_out)
  2518. free(voice_out);
  2519. if (speed_out)
  2520. free(speed_out);
  2521. return true;
  2522. }
  2523. #endif
  2524. frontend_ctx_driver_t frontend_ctx_unix = {
  2525. frontend_unix_get_env, /* get_env */
  2526. frontend_unix_init, /* init */
  2527. frontend_unix_deinit, /* deinit */
  2528. #ifdef ANDROID
  2529. NULL, /* exitspawn */
  2530. #else
  2531. frontend_unix_exitspawn, /* exitspawn */
  2532. #endif
  2533. NULL, /* process_args */
  2534. #ifdef ANDROID
  2535. NULL, /* exec */
  2536. NULL, /* set_fork */
  2537. #else
  2538. frontend_unix_exec, /* exec */
  2539. frontend_unix_set_fork, /* set_fork */
  2540. #endif
  2541. #ifdef ANDROID
  2542. frontend_android_shutdown, /* shutdown */
  2543. frontend_android_get_name, /* get_name */
  2544. #else
  2545. NULL, /* shutdown */
  2546. NULL, /* get_name */
  2547. #endif
  2548. frontend_unix_get_os,
  2549. frontend_unix_get_rating, /* get_rating */
  2550. NULL, /* content_loaded */
  2551. frontend_unix_get_arch, /* get_architecture */
  2552. frontend_unix_get_powerstate,
  2553. frontend_unix_parse_drive_list,
  2554. frontend_unix_get_total_mem,
  2555. frontend_unix_get_free_mem,
  2556. frontend_unix_install_signal_handlers,
  2557. frontend_unix_get_signal_handler_state,
  2558. frontend_unix_set_signal_handler_state,
  2559. frontend_unix_destroy_signal_handler_state,
  2560. NULL, /* attach_console */
  2561. NULL, /* detach_console */
  2562. #ifdef HAVE_LAKKA
  2563. frontend_unix_get_lakka_version, /* get_lakka_version */
  2564. #else
  2565. NULL, /* get_lakka_version */
  2566. #endif
  2567. #if defined(HAVE_LAKKA_SWITCH) || (defined(HAVE_LAKKA) && defined(HAVE_ODROIDGO2))
  2568. frontend_unix_set_screen_brightness,/* set_screen_brightness */
  2569. #else
  2570. NULL, /* set_screen_brightness */
  2571. #endif
  2572. frontend_unix_watch_path_for_changes,
  2573. frontend_unix_check_for_path_changes,
  2574. frontend_unix_set_sustained_performance_mode,
  2575. frontend_unix_get_cpu_model_name,
  2576. frontend_unix_get_user_language,
  2577. #if (defined(__linux__) || defined(__unix__)) && !defined(ANDROID)
  2578. is_narrator_running_unix, /* is_narrator_running */
  2579. accessibility_speak_unix, /* accessibility_speak */
  2580. #else
  2581. NULL, /* is_narrator_running */
  2582. NULL, /* accessibility_speak */
  2583. #endif
  2584. #ifdef FERAL_GAMEMODE
  2585. frontend_unix_set_gamemode,
  2586. #else
  2587. NULL,
  2588. #endif
  2589. #ifdef ANDROID
  2590. "android", /* ident */
  2591. #else
  2592. "unix", /* ident */
  2593. #endif
  2594. NULL /* get_video_driver */
  2595. };