platform_unix.c 105 KB

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