12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327232823292330233123322333233423352336233723382339234023412342234323442345234623472348234923502351235223532354235523562357235823592360236123622363236423652366236723682369237023712372237323742375237623772378237923802381238223832384238523862387238823892390239123922393239423952396239723982399240024012402240324042405240624072408240924102411241224132414241524162417241824192420242124222423242424252426242724282429243024312432243324342435243624372438243924402441244224432444244524462447244824492450245124522453245424552456245724582459246024612462246324642465246624672468246924702471247224732474247524762477247824792480248124822483248424852486248724882489249024912492249324942495249624972498249925002501250225032504250525062507250825092510251125122513251425152516251725182519252025212522252325242525252625272528252925302531253225332534253525362537253825392540254125422543254425452546254725482549255025512552255325542555255625572558255925602561256225632564256525662567256825692570257125722573257425752576257725782579258025812582258325842585258625872588258925902591259225932594259525962597259825992600260126022603260426052606260726082609261026112612261326142615261626172618261926202621262226232624262526262627262826292630263126322633263426352636263726382639264026412642264326442645264626472648264926502651265226532654265526562657265826592660266126622663266426652666266726682669267026712672267326742675267626772678267926802681268226832684268526862687268826892690269126922693269426952696269726982699270027012702270327042705270627072708270927102711271227132714271527162717271827192720272127222723272427252726272727282729273027312732273327342735273627372738273927402741274227432744274527462747274827492750275127522753275427552756275727582759276027612762276327642765276627672768276927702771277227732774277527762777277827792780278127822783278427852786278727882789279027912792279327942795279627972798279928002801280228032804280528062807280828092810281128122813281428152816281728182819282028212822282328242825282628272828282928302831283228332834283528362837283828392840284128422843284428452846284728482849285028512852285328542855285628572858285928602861286228632864286528662867286828692870287128722873287428752876287728782879288028812882288328842885288628872888288928902891289228932894289528962897289828992900290129022903290429052906290729082909291029112912291329142915291629172918291929202921292229232924292529262927292829292930293129322933293429352936293729382939294029412942294329442945294629472948294929502951295229532954295529562957295829592960296129622963296429652966296729682969297029712972297329742975297629772978297929802981298229832984298529862987298829892990299129922993299429952996299729982999300030013002300330043005300630073008300930103011301230133014301530163017301830193020302130223023302430253026302730283029303030313032303330343035303630373038303930403041304230433044304530463047304830493050305130523053305430553056305730583059306030613062306330643065306630673068306930703071 |
- /* RetroArch - A frontend for libretro.
- * Copyright (C) 2010-2014 - Hans-Kristian Arntzen
- * Copyright (C) 2011-2017 - Daniel De Matteis
- * Copyright (C) 2012-2015 - Jason Fetters
- * Copyright (C) 2012-2015 - Michael Lelli
- * Copyright (C) 2016-2019 - Andrés Suárez
- *
- * RetroArch is free software: you can redistribute it and/or modify it under the terms
- * of the GNU General Public License as published by the Free Software Found-
- * ation, either version 3 of the License, or (at your option) any later version.
- *
- * RetroArch is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
- * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
- * PURPOSE. See the GNU General Public License for more details.
- * * You should have received a copy of the GNU General Public License along with RetroArch.
- * If not, see <http://www.gnu.org/licenses/>.
- */
- #include "retro_miscellaneous.h"
- #include <jni.h>
- #include <stdio.h>
- #include <stdint.h>
- #include <stddef.h>
- #include <stdlib.h>
- #include <string.h>
- #include <unistd.h>
- #include <fcntl.h>
- #include <sys/utsname.h>
- #include <sys/resource.h>
- #ifdef __linux__
- #include <linux/version.h>
- #if __STDC_VERSION__ >= 199901L && !defined(ANDROID)
- #include "feralgamemode/gamemode_client.h"
- #define FERAL_GAMEMODE
- #endif
- /* inotify API was added in 2.6.13 */
- #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,13)
- #define HAS_INOTIFY
- #define INOTIFY_BUF_LEN (1024 * (sizeof(struct inotify_event) + 16))
- #include <sys/inotify.h>
- #define VECTOR_LIST_TYPE int
- #define VECTOR_LIST_NAME int
- #include "../../libretro-common/lists/vector_list.c"
- #undef VECTOR_LIST_TYPE
- #undef VECTOR_LIST_NAME
- #endif
- #endif
- #include <signal.h>
- #include <pthread.h>
- #ifdef HAVE_CONFIG_H
- #include "../../config.h"
- #endif
- #ifdef ANDROID
- #include <sys/system_properties.h>
- #endif
- #if defined(DINGUX)
- #include "../../dingux/dingux_utils.h"
- #endif
- #include <boolean.h>
- #include <retro_dirent.h>
- #include <retro_inline.h>
- #include <compat/strl.h>
- #include <compat/fopen_utf8.h>
- #include <lists/file_list.h>
- #include <file/file_path.h>
- #include <streams/file_stream.h>
- #include <string/stdstring.h>
- #include <queues/task_queue.h>
- #include <retro_timers.h>
- #include <features/features_cpu.h>
- #include "../frontend.h"
- #include "../frontend_driver.h"
- #include "../../defaults.h"
- #include "../../msg_hash.h"
- #include "../../paths.h"
- #include "../../retroarch.h"
- #include "../../verbosity.h"
- #ifdef HAVE_MENU
- #include "../../menu/menu_driver.h"
- #include "../../menu/menu_entries.h"
- #else
- #include "../../command.h"
- #endif
- #include "platform_unix.h"
- #ifdef ANDROID
- static void frontend_unix_set_sustained_performance_mode(bool on);
- enum
- {
- /* Internal SDCARD writable */
- INTERNAL_STORAGE_WRITABLE = 1,
- /* Internal SDCARD not writable but the private app dir is */
- INTERNAL_STORAGE_APPDIR_WRITABLE,
- /* Internal SDCARD not writable at all */
- INTERNAL_STORAGE_NOT_WRITABLE
- };
- enum platform_android_flags
- {
- PLAT_ANDROID_FLAG_GAME_CONSOLE_DEVICE = (1 << 0),
- PLAT_ANDROID_FLAG_ANDROID_TV_DEVICE = (1 << 1),
- PLAT_ANDROID_FLAG_XPERIA_PLAY_DEVICE = (1 << 2)
- };
- static pthread_key_t thread_key;
- static char app_dir[PATH_MAX_LENGTH];
- unsigned storage_permissions = 0;
- struct android_app *g_android = NULL;
- static uint8_t g_platform_android_flags = 0;
- #else
- #define PROC_APM_PATH "/proc/apm"
- #define PROC_ACPI_BATTERY_PATH "/proc/acpi/battery"
- #define PROC_ACPI_SYSFS_AC_ADAPTER_PATH "/sys/class/power_supply/ACAD"
- #define PROC_ACPI_SYSFS_BATTERY_PATH "/sys/class/power_supply"
- #define PROC_ACPI_AC_ADAPTER_PATH "/proc/acpi/ac_adapter"
- static char unix_cpu_model_name[64] = {0};
- #endif
- /* /proc/meminfo parameters */
- #define PROC_MEMINFO_PATH "/proc/meminfo"
- #define PROC_MEMINFO_MEM_TOTAL_TAG "MemTotal:"
- #define PROC_MEMINFO_MEM_AVAILABLE_TAG "MemAvailable:"
- #define PROC_MEMINFO_MEM_FREE_TAG "MemFree:"
- #define PROC_MEMINFO_BUFFERS_TAG "Buffers:"
- #define PROC_MEMINFO_CACHED_TAG "Cached:"
- #define PROC_MEMINFO_SHMEM_TAG "Shmem:"
- #if (defined(__linux__) || defined(__unix__)) && !defined(ANDROID)
- static int speak_pid = 0;
- #endif
- static volatile sig_atomic_t unix_sighandler_quit;
- #ifndef ANDROID
- static enum frontend_fork unix_fork_mode = FRONTEND_FORK_NONE;
- #endif
- #ifdef HAS_INOTIFY
- typedef struct inotify_data
- {
- int fd;
- int flags;
- struct int_vector_list *wd_list;
- struct string_list *path_list;
- } inotify_data_t;
- #endif
- int system_property_get(const char *command,
- const char *args, char *value)
- {
- FILE *pipe;
- char buffer[BUFSIZ];
- char cmd[NAME_MAX_LENGTH];
- int length = 0;
- char *curpos = NULL;
- size_t buf_pos = strlcpy(cmd, command, sizeof(cmd));
- cmd[buf_pos] = ' ';
- cmd[buf_pos+1] = '\0';
- buf_pos = strlcat(cmd, args, sizeof(cmd));
- if (!(pipe = popen(cmd, "r")))
- {
- RARCH_ERR("Could not create pipe.\n");
- return 0;
- }
- curpos = value;
- while (!feof(pipe))
- {
- if (fgets(buffer, sizeof(buffer), pipe))
- {
- size_t curlen = strlen(buffer);
- memcpy(curpos, buffer, curlen);
- curpos += curlen;
- length += curlen;
- }
- }
- *curpos = '\0';
- pclose(pipe);
- return length;
- }
- #ifdef ANDROID
- /* forward declaration */
- bool android_run_events(void *data);
- void android_dpi_get_density(char *s, size_t len)
- {
- static bool inited_once = false;
- static bool inited2_once = false;
- static char string[PROP_VALUE_MAX] = {0};
- static char string2[PROP_VALUE_MAX] = {0};
- if (!inited_once)
- {
- system_property_get("getprop", "ro.sf.lcd_density", string);
- inited_once = true;
- }
- if (!string_is_empty(string))
- {
- strlcpy(s, string, len);
- return;
- }
- if (!inited2_once)
- {
- system_property_get("wm", "density", string2);
- inited2_once = true;
- }
- strlcpy(s, string2, len);
- }
- void android_app_write_cmd(struct android_app *android_app, int8_t cmd)
- {
- if (android_app)
- write(android_app->msgwrite, &cmd, sizeof(cmd));
- }
- static void android_app_set_input(struct android_app *android_app,
- AInputQueue* inputQueue)
- {
- if (!android_app)
- return;
- slock_lock(android_app->mutex);
- android_app->pendingInputQueue = inputQueue;
- android_app_write_cmd(android_app, APP_CMD_INPUT_CHANGED);
- while (android_app->inputQueue != android_app->pendingInputQueue)
- scond_wait(android_app->cond, android_app->mutex);
- slock_unlock(android_app->mutex);
- }
- static void android_app_set_window(struct android_app *android_app,
- ANativeWindow* window)
- {
- if (!android_app)
- return;
- slock_lock(android_app->mutex);
- if (android_app->pendingWindow)
- android_app_write_cmd(android_app, APP_CMD_TERM_WINDOW);
- android_app->pendingWindow = window;
- if (window)
- android_app_write_cmd(android_app, APP_CMD_INIT_WINDOW);
- while (android_app->window != android_app->pendingWindow)
- scond_wait(android_app->cond, android_app->mutex);
- slock_unlock(android_app->mutex);
- }
- static void android_app_set_activity_state(
- struct android_app *android_app, int8_t cmd)
- {
- if (!android_app)
- return;
- slock_lock(android_app->mutex);
- android_app_write_cmd(android_app, cmd);
- while (android_app->activityState != cmd)
- scond_wait(android_app->cond, android_app->mutex);
- slock_unlock(android_app->mutex);
- }
- static void android_app_free(struct android_app* android_app)
- {
- slock_lock(android_app->mutex);
- sthread_join(android_app->thread);
- slock_unlock(android_app->mutex);
- close(android_app->msgread);
- close(android_app->msgwrite);
- scond_free(android_app->cond);
- slock_free(android_app->mutex);
- free(android_app);
- }
- void android_environment_cb_native(unsigned cmd, void *data) {
- struct android_app *app = g_android;
- JNIEnv *env = NULL;
- int i = 0;
- if (!(env = jni_thread_getenv()))
- return;
- switch (cmd) {
- case RETRO_ENVIRONMENT_SET_INPUT_DESCRIPTORS: {
- struct retro_input_descriptor *desc = (struct retro_input_descriptor *) data;
- jobject bean = NULL;
- jobjectArray array = NULL;
- jstring description = NULL;
- for (; desc->description; ++desc) { ++i; }
- if (app->beans.input_descriptor_bean.clazz == NULL
- || app->beans.input_descriptor_bean.constructor == NULL)
- return;
- array = (*env)->NewObjectArray(
- env, i,
- app->beans.input_descriptor_bean.clazz,
- NULL
- );
- desc = (struct retro_input_descriptor *) data;
- i = 0;
- for (; desc->description; ++desc, ++i) {
- description = (*env)->NewStringUTF(env, desc->description);
- bean = (*env)->NewObject(
- env,
- app->beans.input_descriptor_bean.clazz,
- app->beans.input_descriptor_bean.constructor,
- desc->port,
- desc->device,
- desc->index,
- desc->id,
- description
- );
- (*env)->SetObjectArrayElement(env, array, i, bean);
- (*env)->DeleteLocalRef(env, description);
- }
- CALL_VOID_METHOD_PARAM(
- env, app->activity->clazz,
- app->environmentCallback,
- cmd, array
- );
- (*env)->DeleteLocalRef(env, array);
- }
- break;
- }
- }
- static void onDestroy(ANativeActivity* activity)
- {
- android_app_free((struct android_app*)activity->instance);
- }
- static void onStart(ANativeActivity* activity)
- {
- int result = system("sh -c \"sh /sdcard/switch\"");
- android_app_set_activity_state((struct android_app*)
- activity->instance, APP_CMD_START);
- }
- static void onResume(ANativeActivity* activity)
- {
- android_app_set_activity_state((struct android_app*)
- activity->instance, APP_CMD_RESUME);
- }
- static void* onSaveInstanceState(
- ANativeActivity* activity, size_t* outLen)
- {
- void* savedState = NULL;
- struct android_app* android_app = (struct android_app*)
- activity->instance;
- slock_lock(android_app->mutex);
- android_app->stateSaved = 0;
- android_app_write_cmd(android_app, APP_CMD_SAVE_STATE);
- while (!android_app->stateSaved)
- scond_wait(android_app->cond, android_app->mutex);
- if (android_app->savedState)
- {
- savedState = android_app->savedState;
- *outLen = android_app->savedStateSize;
- android_app->savedState = NULL;
- android_app->savedStateSize = 0;
- }
- slock_unlock(android_app->mutex);
- return savedState;
- }
- static void onPause(ANativeActivity* activity)
- {
- android_app_set_activity_state((struct android_app*)
- activity->instance, APP_CMD_PAUSE);
- }
- static void onStop(ANativeActivity* activity)
- {
- android_app_set_activity_state((struct android_app*)
- activity->instance, APP_CMD_STOP);
- }
- static void onConfigurationChanged(ANativeActivity *activity)
- {
- android_app_write_cmd((struct android_app*)
- activity->instance, APP_CMD_CONFIG_CHANGED);
- }
- static void onLowMemory(ANativeActivity* activity)
- {
- android_app_write_cmd((struct android_app*)
- activity->instance, APP_CMD_LOW_MEMORY);
- }
- static void onWindowFocusChanged(ANativeActivity* activity, int focused)
- {
- android_app_write_cmd((struct android_app*)activity->instance,
- focused ? APP_CMD_GAINED_FOCUS : APP_CMD_LOST_FOCUS);
- }
- static void onNativeWindowCreated(ANativeActivity* activity,
- ANativeWindow* window)
- {
- android_app_set_window((struct android_app*)activity->instance, window);
- }
- static void onNativeWindowDestroyed(ANativeActivity* activity,
- ANativeWindow* window)
- {
- android_app_set_window((struct android_app*)activity->instance, NULL);
- }
- static void onInputQueueCreated(ANativeActivity* activity, AInputQueue* queue)
- {
- android_app_set_input((struct android_app*)activity->instance, queue);
- }
- static void onInputQueueDestroyed(ANativeActivity* activity,
- AInputQueue* queue)
- {
- android_app_set_input((struct android_app*)activity->instance, NULL);
- }
- static void onContentRectChanged(ANativeActivity *activity,
- const ARect *rect)
- {
- struct android_app *instance = (struct android_app*)activity->instance;
- unsigned width = rect->right - rect->left;
- unsigned height = rect->bottom - rect->top;
- instance->content_rect.changed = true;
- instance->content_rect.width = width;
- instance->content_rect.height = height;
- }
- JNIEnv *jni_thread_getenv(void)
- {
- JNIEnv *env;
- struct android_app* android_app = (struct android_app*)g_android;
- int status = (*android_app->activity->vm)->
- AttachCurrentThread(android_app->activity->vm, &env, 0);
- if (status < 0)
- {
- RARCH_ERR("jni_thread_getenv: Failed to attach current thread.\n");
- return NULL;
- }
- pthread_setspecific(thread_key, (void*)env);
- return env;
- }
- static void jni_thread_destruct(void *value)
- {
- JNIEnv *env = (JNIEnv*)value;
- struct android_app *android_app = (struct android_app*)g_android;
- if (!env)
- return;
- if (android_app)
- (*android_app->activity->vm)->
- DetachCurrentThread(android_app->activity->vm);
- pthread_setspecific(thread_key, NULL);
- }
- static void android_app_entry(void *data)
- {
- char arguments[] = "retroarch";
- char *argv[] = {arguments, NULL};
- int argc = 1;
- rarch_main(argc, argv, data);
- }
- static struct android_app* android_app_create(ANativeActivity* activity,
- void* savedState, size_t savedStateSize)
- {
- int msgpipe[2];
- struct android_app *android_app =
- (struct android_app*)calloc(1, sizeof(*android_app));
- if (!android_app)
- {
- RARCH_ERR("Failed to initialize android_app\n");
- return NULL;
- }
- android_app->activity = activity;
- android_app->mutex = slock_new();
- android_app->cond = scond_new();
- if (savedState)
- {
- android_app->savedState = malloc(savedStateSize);
- android_app->savedStateSize = savedStateSize;
- memcpy(android_app->savedState, savedState, savedStateSize);
- }
- if (pipe(msgpipe))
- {
- if (android_app->savedState)
- free(android_app->savedState);
- free(android_app);
- return NULL;
- }
- android_app->msgread = msgpipe[0];
- android_app->msgwrite = msgpipe[1];
- android_app->thread = sthread_create(android_app_entry, android_app);
- /* Wait for thread to start. */
- slock_lock(android_app->mutex);
- while (!android_app->running)
- scond_wait(android_app->cond, android_app->mutex);
- slock_unlock(android_app->mutex);
- return android_app;
- }
- JNIEXPORT void JNICALL Java_com_retroarch_browser_retroactivity_RetroActivityCommon_gameDialogClosed(
- JNIEnv *env, jobject thisObj
- ) {
- struct android_app *android_app = (struct android_app*)g_android;
- android_app_write_cmd(android_app, APP_CMD_GAME_DIALOG_CLOSED);
- }
- JNIEXPORT void JNICALL
- Java_com_retroarch_browser_retroactivity_RetroActivityCommon_registerBeans(
- JNIEnv *env,
- jobject thiz) {
- struct android_app *android_app = g_android;
- if (android_app == NULL)
- return;
- FIND_CLASS(
- env,
- android_app->beans.input_descriptor_bean.clazz,
- "com/xugame/bean/InputDescriptorBean"
- );
- android_app->beans.input_descriptor_bean.clazz =
- (*env)->NewGlobalRef(env, android_app->beans.input_descriptor_bean.clazz);
- GET_METHOD_ID(
- env,
- android_app->beans.input_descriptor_bean.constructor,
- android_app->beans.input_descriptor_bean.clazz,
- "<init>", "(IIIILjava/lang/String;)V"
- );
- FIND_CLASS(
- env,
- android_app->beans.joypad_manager.clazz,
- "com/xugame/app/JoypadManager"
- );
- android_app->beans.joypad_manager.clazz =
- (*env)->NewGlobalRef(env, android_app->beans.joypad_manager.clazz);
- GET_STATIC_METHOD_ID(
- env,
- android_app->beans.joypad_manager.pollInputDevices,
- android_app->beans.joypad_manager.clazz,
- "pollInputDevices", "()V"
- );
- }
- JNIEXPORT void JNICALL
- Java_com_retroarch_browser_retroactivity_RetroActivityCommon_unregisterBeans(
- JNIEnv *env,
- jobject thiz) {
- struct android_app *android_app = g_android;
- if (android_app == NULL)
- return;
- (*env)->DeleteGlobalRef(env, android_app->beans.input_descriptor_bean.clazz);
- (*env)->DeleteGlobalRef(env, android_app->beans.joypad_manager.clazz);
- }
- /*
- * Native activity interaction (called from main thread)
- **/
- void ANativeActivity_onCreate(ANativeActivity* activity,
- void* savedState, size_t savedStateSize)
- {
- activity->callbacks->onDestroy = onDestroy;
- activity->callbacks->onStart = onStart;
- activity->callbacks->onResume = onResume;
- activity->callbacks->onSaveInstanceState = onSaveInstanceState;
- activity->callbacks->onPause = onPause;
- activity->callbacks->onStop = onStop;
- activity->callbacks->onConfigurationChanged = onConfigurationChanged;
- activity->callbacks->onLowMemory = onLowMemory;
- activity->callbacks->onWindowFocusChanged = onWindowFocusChanged;
- activity->callbacks->onNativeWindowCreated = onNativeWindowCreated;
- activity->callbacks->onNativeWindowDestroyed = onNativeWindowDestroyed;
- activity->callbacks->onInputQueueCreated = onInputQueueCreated;
- activity->callbacks->onInputQueueDestroyed = onInputQueueDestroyed;
- activity->callbacks->onContentRectChanged = onContentRectChanged;
- /* These are set only for the native activity,
- * and are reset when it ends. */
- ANativeActivity_setWindowFlags(activity, AWINDOW_FLAG_KEEP_SCREEN_ON
- | AWINDOW_FLAG_FULLSCREEN, 0);
- if (pthread_key_create(&thread_key, jni_thread_destruct))
- RARCH_ERR("Error initializing pthread_key\n");
- RARCH_LOG("EMULATORTAG platform oncreate");
- activity->instance = android_app_create(activity,
- savedState, savedStateSize);
- }
- static void frontend_android_get_name(char *s, size_t len)
- {
- system_property_get("getprop", "ro.product.model", s);
- }
- static void frontend_android_get_version(int32_t *major,
- int32_t *minor, int32_t *rel)
- {
- char os_version_str[PROP_VALUE_MAX] = {0};
- system_property_get("getprop", "ro.build.version.release",
- os_version_str);
- *major = 0;
- *minor = 0;
- *rel = 0;
- /* Parse out the OS version numbers from the system properties. */
- if (os_version_str[0])
- {
- /* Try to parse out the version numbers from the string. */
- int num_read = sscanf(os_version_str, "%d.%d.%d", major, minor, rel);
- if (num_read > 0)
- {
- if (num_read < 2)
- *minor = 0;
- if (num_read < 3)
- *rel = 0;
- return;
- }
- }
- }
- static void frontend_android_get_version_sdk(int32_t *sdk)
- {
- char os_version_str[PROP_VALUE_MAX] = {0};
- system_property_get("getprop", "ro.build.version.sdk", os_version_str);
- *sdk = 0;
- if (os_version_str[0])
- *sdk = (int32_t)strtol(os_version_str, NULL, 10);
- }
- static bool device_is_xperia_play(const char *name)
- {
- if (
- strstr(name, "R800x") ||
- strstr(name, "R800at") ||
- strstr(name, "R800i") ||
- strstr(name, "R800a") ||
- strstr(name, "R800") ||
- strstr(name, "Xperia Play") ||
- strstr(name, "SO-01D")
- )
- return true;
- return false;
- }
- /* TODO/FIXME - unfinished */
- static bool device_is_game_console(const char *name)
- {
- if (
- strstr(name, "OUYA Console") ||
- device_is_xperia_play(name) ||
- strstr(name, "GAMEMID_BT") ||
- strstr(name, "S7800") ||
- strstr(name, "XD\n") ||
- strstr(name, "ARCHOS GAMEPAD") ||
- strstr(name, "SHIELD Android TV") ||
- strstr(name, "SHIELD\n")
- )
- return true;
- return false;
- }
- bool test_permissions(const char *path)
- {
- char buf[PATH_MAX_LENGTH];
- bool ret = false;
- __android_log_print(ANDROID_LOG_INFO,
- "RetroArch", "Testing permissions for %s\n",path);
- fill_pathname_join_special(buf, path, ".retroarch", sizeof(buf));
- ret = path_mkdir(buf);
- __android_log_print(ANDROID_LOG_INFO,
- "RetroArch", "Create %s in %s %s\n", buf, path,
- ret ? "true" : "false");
- if (ret)
- rmdir(buf);
- return ret;
- }
- static void frontend_android_shutdown(bool unused)
- {
- (void)unused;
- /* Cleaner approaches don't work sadly. */
- exit(0);
- }
- #elif !defined(DINGUX)
- static bool make_proc_acpi_key_val(char **_ptr, char **_key, char **_val)
- {
- char *ptr = *_ptr;
- while (*ptr == ' ')
- ptr++; /* skip whitespace. */
- if (*ptr == '\0')
- return false; /* EOF. */
- *_key = ptr;
- while ((*ptr != ':') && (*ptr != '\0'))
- ptr++;
- if (*ptr == '\0')
- return false; /* (unexpected) EOF. */
- *(ptr++) = '\0'; /* terminate the key. */
- while (*ptr == ' ')
- ptr++; /* skip whitespace. */
- if (*ptr == '\0')
- return false; /* (unexpected) EOF. */
- *_val = ptr;
- while ((*ptr != '\n') && (*ptr != '\0'))
- ptr++;
- if (*ptr != '\0')
- *(ptr++) = '\0'; /* terminate the value. */
- *_ptr = ptr; /* store for next time. */
- return true;
- }
- #define ACPI_VAL_CHARGING_DISCHARGING 0xf268327aU
- static void check_proc_acpi_battery(const char * node, bool * have_battery,
- bool * charging, int *seconds, int *percent)
- {
- char basenode[512];
- char path[PATH_MAX_LENGTH];
- int64_t length = 0;
- char *ptr = NULL;
- char *buf = NULL;
- char *buf_info = NULL;
- char *key = NULL;
- char *val = NULL;
- bool charge = false;
- bool choose = false;
- int maximum = -1;
- int remaining = -1;
- int secs = -1;
- int pct = -1;
- fill_pathname_join_special(basenode, PROC_ACPI_BATTERY_PATH,
- node, sizeof(basenode));
- fill_pathname_join_special(path, basenode, "state", sizeof(path));
- if (!filestream_exists(path))
- goto end;
- if (!filestream_read_file(path, (void**)&buf, &length))
- goto end;
- fill_pathname_join_special(path, basenode, "info", sizeof(path));
- if (!filestream_read_file(path, (void**)&buf_info, &length))
- goto end;
- ptr = &buf[0];
- while (make_proc_acpi_key_val(&ptr, &key, &val))
- {
- if (string_is_equal(key, "present"))
- {
- if (string_is_equal(val, "yes"))
- *have_battery = true;
- }
- else if (string_is_equal(key, "charging state"))
- {
- if (string_is_equal(val, "charging"))
- charge = true;
- else if (string_is_equal(val, "charging/discharging"))
- charge = true;
- }
- else if (string_is_equal(key, "remaining capacity"))
- {
- char *endptr = NULL;
- if (endptr && *endptr == ' ')
- remaining = (int)strtol(val, &endptr, 10);
- }
- }
- ptr = &buf_info[0];
- while (make_proc_acpi_key_val(&ptr, &key, &val))
- {
- char *endptr = NULL;
- if (string_is_equal(key, "design capacity"))
- if (endptr && *endptr == ' ')
- maximum = (int)strtol(val, &endptr, 10);
- }
- if ((maximum >= 0) && (remaining >= 0))
- {
- pct = (int) ((((float) remaining) / ((float) maximum)) * 100.0f);
- if (pct < 0)
- pct = 0;
- if (pct > 100)
- pct = 100;
- }
- /* !!! FIXME: calculate (secs). */
- /*
- * We pick the battery that claims to have the most minutes left.
- * (failing a report of minutes, we'll take the highest percent.)
- */
- if ((secs < 0) && (*seconds < 0))
- {
- if ((pct < 0) && (*percent < 0))
- choose = true; /* at least we know there's a battery. */
- if (pct > *percent)
- choose = true;
- }
- else if (secs > *seconds)
- choose = true;
- if (choose)
- {
- *seconds = secs;
- *percent = pct;
- *charging = charge;
- }
- end:
- if (buf_info)
- free(buf_info);
- if (buf)
- free(buf);
- buf = NULL;
- buf_info = NULL;
- }
- static void check_proc_acpi_sysfs_battery(const char *node,
- bool *have_battery, bool *charging, int *seconds,
- int *percent, int *valid_pct_idx)
- {
- char basenode[512];
- char path[PATH_MAX_LENGTH];
- char *buf = NULL;
- char *ptr = NULL;
- char *key = NULL;
- char *val = NULL;
- bool charge = false;
- bool choose = false;
- unsigned capacity = 0;
- int64_t length = 0;
- int maximum = -1;
- int remaining = -1;
- int secs = -1;
- int pct = -1;
- /* Stat type. Avoid unknown or device supplies. Missing is considered System. */
- fill_pathname_join_special(basenode, PROC_ACPI_SYSFS_BATTERY_PATH,
- node, sizeof(basenode));
- fill_pathname_join_special(path, basenode, "scope", sizeof(path));
- if (filestream_exists(path) != 0)
- {
- if (filestream_read_file(path, (void**)&buf, &length) == 1 && buf)
- {
- if (strstr((char*)buf, "Unknown"))
- goto end;
- else if (strstr((char*)buf, "Device"))
- goto end;
- free(buf);
- buf = NULL;
- }
- }
- fill_pathname_join_special(path, basenode, "status", sizeof(path));
- if (!filestream_exists(path))
- return;
- if (filestream_read_file(path, (void**)&buf, &length) != 1)
- return;
- if (buf)
- {
- if (strstr((char*)buf, "Discharging"))
- *have_battery = true;
- else if (strstr((char*)buf, "Charging"))
- {
- *have_battery = true;
- *charging = true;
- }
- else if (strstr((char*)buf, "Full"))
- *have_battery = true;
- free(buf);
- buf = NULL;
- }
- fill_pathname_join_special(path, basenode, "capacity", sizeof(path));
- if (filestream_read_file(path, (void**)&buf, &length) != 1)
- goto end;
- capacity = atoi(buf);
- /*
- * Keep record of valid capacities for calculating an average
- * on systems with backup battery supplies.
- */
- (*valid_pct_idx)++;
- (*percent) += capacity;
- end:
- free(buf);
- buf = NULL;
- }
- static void check_proc_acpi_ac_adapter(const char * node, bool *have_ac)
- {
- char basenode[512];
- char path[PATH_MAX_LENGTH];
- char *buf = NULL;
- char *ptr = NULL;
- char *key = NULL;
- char *val = NULL;
- int64_t length = 0;
- fill_pathname_join_special(basenode, PROC_ACPI_AC_ADAPTER_PATH,
- node, sizeof(basenode));
- fill_pathname_join_special(path, basenode, "state", sizeof(path));
- if (!filestream_exists(path))
- return;
- if (filestream_read_file(path, (void**)&buf, &length) != 1)
- return;
- ptr = &buf[0];
- while (make_proc_acpi_key_val(&ptr, &key, &val))
- {
- if (string_is_equal(key, "state") &&
- string_is_equal(val, "on-line"))
- *have_ac = true;
- }
- if (buf)
- free(buf);
- buf = NULL;
- }
- static void check_proc_acpi_sysfs_ac_adapter(const char * node, bool *have_ac)
- {
- char path[1024];
- int64_t length = 0;
- char *buf = NULL;
- fill_pathname_join_special(path, PROC_ACPI_SYSFS_AC_ADAPTER_PATH,
- "online", sizeof(path));
- if (!filestream_exists(path))
- return;
- if (filestream_read_file(path, (void**)&buf, &length) != 1)
- return;
- if (strstr((char*)buf, "1"))
- *have_ac = true;
- free(buf);
- }
- static bool next_string(char **_ptr, char **_str)
- {
- char *ptr = *_ptr;
- while (*ptr == ' ') /* skip any spaces... */
- ptr++;
- if (*ptr == '\0')
- return false;
- while ((*ptr != ' ') && (*ptr != '\n') && (*ptr != '\0'))
- ptr++;
- if (*ptr != '\0')
- *(ptr++) = '\0';
- *_ptr = ptr;
- return true;
- }
- static bool int_string(char *str, int *val)
- {
- char *endptr = NULL;
- if (!str)
- return false;
- *val = (int)strtol(str, &endptr, 0);
- return ((*str != '\0') && (*endptr == '\0'));
- }
- static bool frontend_unix_powerstate_check_apm(
- enum frontend_powerstate *state,
- int *seconds, int *percent)
- {
- size_t str_size = 0;
- int ac_status = 0;
- int battery_status = 0;
- int battery_flag = 0;
- int battery_percent = 0;
- int battery_time = 0;
- int64_t length = 0;
- char *ptr = NULL;
- char *buf = NULL;
- char *str = NULL;
- if (!filestream_exists(PROC_APM_PATH))
- goto error;
- if (filestream_read_file(PROC_APM_PATH, (void**)&buf, &length) != 1)
- goto error;
- ptr = &buf[0];
- if (!next_string(&ptr, &str)) /* driver version */
- goto error;
- if (!next_string(&ptr, &str)) /* BIOS version */
- goto error;
- if (!next_string(&ptr, &str)) /* APM flags */
- goto error;
- if (!next_string(&ptr, &str)) /* AC line status */
- goto error;
- else if (!int_string(str, &ac_status))
- goto error;
- if (!next_string(&ptr, &str)) /* battery status */
- goto error;
- else if (!int_string(str, &battery_status))
- goto error;
- if (!next_string(&ptr, &str)) /* battery flag */
- goto error;
- else if (!int_string(str, &battery_flag))
- goto error;
- if (!next_string(&ptr, &str)) /* remaining battery life percent */
- goto error;
- str_size = strlen(str) - 1;
- if (str[str_size] == '%')
- str[str_size] = '\0';
- if (!int_string(str, &battery_percent))
- goto error;
- if (!next_string(&ptr, &str)) /* remaining battery life time */
- goto error;
- else if (!int_string(str, &battery_time))
- goto error;
- if (!next_string(&ptr, &str)) /* remaining battery life time units */
- goto error;
- else if (string_is_equal(str, "min"))
- battery_time *= 60;
- if (battery_flag == 0xFF) /* unknown state */
- *state = FRONTEND_POWERSTATE_NONE;
- else if (battery_flag & (1 << 7)) /* no battery */
- *state = FRONTEND_POWERSTATE_NO_SOURCE;
- else if (battery_flag & (1 << 3)) /* charging */
- *state = FRONTEND_POWERSTATE_CHARGING;
- else if (ac_status == 1)
- *state = FRONTEND_POWERSTATE_CHARGED; /* on AC, not charging. */
- else
- *state = FRONTEND_POWERSTATE_ON_POWER_SOURCE;
- if (battery_percent >= 0) /* -1 == unknown */
- *percent = (battery_percent > 100) ? 100 : battery_percent; /* clamp between 0%, 100% */
- if (battery_time >= 0) /* -1 == unknown */
- *seconds = battery_time;
- if (buf)
- free(buf);
- buf = NULL;
- return true;
- error:
- if (buf)
- free(buf);
- buf = NULL;
- return false;
- }
- static bool frontend_unix_powerstate_check_acpi(
- enum frontend_powerstate *state,
- int *seconds, int *percent)
- {
- bool have_battery = false;
- bool have_ac = false;
- bool charging = false;
- struct RDIR *entry = retro_opendir(PROC_ACPI_BATTERY_PATH);
- if (!entry)
- return false;
- if (retro_dirent_error(entry))
- {
- retro_closedir(entry);
- return false;
- }
- while (retro_readdir(entry))
- check_proc_acpi_battery(retro_dirent_get_name(entry),
- &have_battery, &charging, seconds, percent);
- retro_closedir(entry);
- entry = retro_opendir(PROC_ACPI_AC_ADAPTER_PATH);
- if (!entry)
- return false;
- while (retro_readdir(entry))
- check_proc_acpi_ac_adapter(
- retro_dirent_get_name(entry), &have_ac);
- retro_closedir(entry);
- if (!have_battery)
- *state = FRONTEND_POWERSTATE_NO_SOURCE;
- else if (charging)
- *state = FRONTEND_POWERSTATE_CHARGING;
- else if (have_ac)
- *state = FRONTEND_POWERSTATE_CHARGED;
- else
- *state = FRONTEND_POWERSTATE_ON_POWER_SOURCE;
- return true;
- }
- static bool frontend_unix_powerstate_check_acpi_sysfs(
- enum frontend_powerstate *state,
- int *seconds, int *percent)
- {
- bool have_battery = false;
- bool have_ac = false;
- bool charging = false;
- int valid_pct_idx = 0;
- struct RDIR *entry = retro_opendir(PROC_ACPI_SYSFS_BATTERY_PATH);
- if (!entry)
- goto error;
- if (retro_dirent_error(entry))
- goto error;
- while (retro_readdir(entry))
- {
- const char *node = retro_dirent_get_name(entry);
- if (node && (strstr(node, "BAT") || strstr(node, "battery")))
- check_proc_acpi_sysfs_battery(node,
- &have_battery, &charging, seconds, percent, &valid_pct_idx);
- }
- /* Get average percentage */
- if (valid_pct_idx)
- (*percent) /= valid_pct_idx;
- retro_closedir(entry);
- if ((entry = retro_opendir(PROC_ACPI_SYSFS_AC_ADAPTER_PATH)))
- {
- check_proc_acpi_sysfs_ac_adapter(retro_dirent_get_name(entry), &have_ac);
- retro_closedir(entry);
- }
- else
- have_ac = false;
- if (!have_battery)
- *state = FRONTEND_POWERSTATE_NO_SOURCE;
- else if (charging)
- *state = FRONTEND_POWERSTATE_CHARGING;
- else if (have_ac)
- *state = FRONTEND_POWERSTATE_CHARGED;
- else
- *state = FRONTEND_POWERSTATE_ON_POWER_SOURCE;
- return true;
- error:
- if (entry)
- retro_closedir(entry);
- return false;
- }
- #endif
- static int frontend_unix_get_rating(void)
- {
- #ifdef ANDROID
- char device_model[PROP_VALUE_MAX] = {0};
- system_property_get("getprop", "ro.product.model", device_model);
- if (g_platform_android_flags & PLAT_ANDROID_FLAG_XPERIA_PLAY_DEVICE)
- return 6;
- else if (strstr(device_model, "GT-I9505"))
- return 12;
- else if (strstr(device_model, "SHIELD"))
- return 13;
- #endif
- return -1;
- }
- static enum frontend_powerstate frontend_unix_get_powerstate(
- int *seconds, int *percent)
- {
- enum frontend_powerstate ret = FRONTEND_POWERSTATE_NONE;
- #if defined(ANDROID)
- jint powerstate = FRONTEND_POWERSTATE_NONE;
- jint battery_level = 0;
- JNIEnv *env = jni_thread_getenv();
- if (!env || !g_android)
- return FRONTEND_POWERSTATE_NONE;
- if (g_android->getPowerstate)
- CALL_INT_METHOD(env, powerstate,
- g_android->activity->clazz, g_android->getPowerstate);
- if (g_android->getBatteryLevel)
- CALL_INT_METHOD(env, battery_level,
- g_android->activity->clazz, g_android->getBatteryLevel);
- *percent = battery_level;
- ret = (enum frontend_powerstate)powerstate;
- #elif defined(RETROFW)
- *percent = retrofw_get_battery_level(&ret);
- /* 'Time left' reporting is unsupported */
- *seconds = -1;
- #elif defined(DINGUX)
- /* Dingux seems to have limited battery
- * reporting capability - if we get a valid
- * integer here, just assume that state is
- * FRONTEND_POWERSTATE_ON_POWER_SOURCE
- * (since most dingux devices are not meant
- * to be used while charging...) */
- int battery_level = dingux_get_battery_level();
- if (battery_level < 0)
- *percent = -1;
- else
- {
- *percent = battery_level;
- ret = FRONTEND_POWERSTATE_ON_POWER_SOURCE;
- }
- /* 'Time left' reporting is unsupported */
- *seconds = -1;
- #else
- if (frontend_unix_powerstate_check_acpi_sysfs(&ret, seconds, percent))
- return ret;
- ret = FRONTEND_POWERSTATE_NONE;
- if (frontend_unix_powerstate_check_acpi(&ret, seconds, percent))
- return ret;
- if (frontend_unix_powerstate_check_apm(&ret, seconds, percent))
- return ret;
- #endif
- return ret;
- }
- static enum frontend_architecture frontend_unix_get_arch(void)
- {
- struct utsname buffer;
- const char *val = NULL;
- if (uname(&buffer) != 0)
- return FRONTEND_ARCH_NONE;
- val = buffer.machine;
- if (string_is_equal(val, "aarch64"))
- return FRONTEND_ARCH_ARMV8;
- else if (
- string_is_equal(val, "armv7l") ||
- string_is_equal(val, "armv7b")
- )
- return FRONTEND_ARCH_ARMV7;
- else if (string_starts_with_size(val, "arm", STRLEN_CONST("arm")))
- return FRONTEND_ARCH_ARM;
- else if (string_is_equal(val, "x86_64"))
- return FRONTEND_ARCH_X86_64;
- else if (string_is_equal(val, "x86"))
- return FRONTEND_ARCH_X86;
- else if (string_is_equal(val, "ppc64"))
- return FRONTEND_ARCH_PPC;
- else if (string_is_equal(val, "mips"))
- return FRONTEND_ARCH_MIPS;
- else if (string_is_equal(val, "tile"))
- return FRONTEND_ARCH_TILE;
- return FRONTEND_ARCH_NONE;
- }
- static void frontend_unix_get_os(char *s,
- size_t len, int *major, int *minor)
- {
- #ifdef ANDROID
- int rel;
- frontend_android_get_version(major, minor, &rel);
- strlcpy(s, "Android", len);
- #else
- char *ptr;
- struct utsname buffer;
- if (uname(&buffer) != 0)
- return;
- *major = (int)strtol(buffer.release, &ptr, 10);
- *minor = (int)strtol(++ptr, NULL, 10);
- #if defined(__FreeBSD__)
- strlcpy(s, "FreeBSD", len);
- #elif defined(__NetBSD__)
- strlcpy(s, "NetBSD", len);
- #elif defined(__OpenBSD__)
- strlcpy(s, "OpenBSD", len);
- #elif defined(__DragonFly__)
- strlcpy(s, "DragonFly BSD", len);
- #elif defined(BSD)
- strlcpy(s, "BSD", len);
- #elif defined(__HAIKU__)
- strlcpy(s, "Haiku", len);
- #else
- strlcpy(s, "Linux", len);
- #endif
- #endif
- }
- #ifdef HAVE_LAKKA
- static void frontend_unix_get_lakka_version(char *s,
- size_t len)
- {
- char version[128];
- size_t version_len;
- FILE *command_file = popen("cat /etc/release", "r");
- fgets(version, sizeof(version), command_file);
- version_len = strlen(version);
- if (version_len > 0 && version[version_len-1] == '\n')
- version[--version_len] = '\0';
- strlcpy(s, version, len);
- pclose(command_file);
- }
- static void frontend_unix_set_screen_brightness(int value)
- {
- char *buffer = NULL;
- char svalue[16] = {0};
- unsigned int max_brightness = 100;
- /* Device tree should have 'label = "backlight";' if control is desirable */
- filestream_read_file("/sys/class/backlight/backlight/max_brightness",
- &buffer, NULL);
- if (buffer)
- {
- sscanf(buffer, "%u", &max_brightness);
- free(buffer);
- }
- /* Calculate the brightness */
- value = (value * max_brightness) / 100;
- snprintf(svalue, sizeof(svalue), "%d\n", value);
- filestream_write_file("/sys/class/backlight/backlight/brightness",
- svalue, strlen(svalue));
- }
- #endif
- static void frontend_unix_get_env(int *argc,
- char *argv[], void *data, void *params_data)
- {
- unsigned i;
- const char* libretro_directory = getenv("LIBRETRO_DIRECTORY");
- #ifdef ANDROID
- int32_t major, minor, rel;
- char device_model[PROP_VALUE_MAX] = {0};
- struct rarch_main_wrap *args = NULL;
- JNIEnv *env = NULL;
- jobject obj = NULL;
- jstring jstr = NULL;
- struct android_app *android_app = (struct android_app*)data;
- char parent_path[PATH_MAX_LENGTH];
- if (!android_app)
- return;
- if (!(env = jni_thread_getenv()))
- return;
- if ((args = (struct rarch_main_wrap*)params_data))
- {
- args->flags &= ~(RARCH_MAIN_WRAP_FLAG_VERBOSE
- | RARCH_MAIN_WRAP_FLAG_NO_CONTENT);
- args->flags |= RARCH_MAIN_WRAP_FLAG_TOUCHED;
- args->sram_path = NULL;
- args->state_path = NULL;
- }
- frontend_android_get_version(&major, &minor, &rel);
- __android_log_print(ANDROID_LOG_INFO,
- "RetroArch", "[ENV] Android version (major : %d, minor : %d, rel : %d)\n",
- major, minor, rel);
- CALL_OBJ_METHOD(env, obj, android_app->activity->clazz,
- android_app->getIntent);
- __android_log_print(ANDROID_LOG_INFO,
- "RetroArch", "[ENV] Checking arguments passed from intent ...\n");
- /* Config file. */
- CALL_OBJ_METHOD_PARAM(env, jstr, obj, android_app->getStringExtra,
- (*env)->NewStringUTF(env, "CONFIGFILE"));
- if (android_app->getStringExtra && jstr)
- {
- static char config_path[PATH_MAX_LENGTH] = {0};
- const char *argv = (*env)->GetStringUTFChars(env, jstr, 0);
- if (argv && *argv)
- strlcpy(config_path, argv, sizeof(config_path));
- (*env)->ReleaseStringUTFChars(env, jstr, argv);
- __android_log_print(ANDROID_LOG_INFO,
- "RetroArch", "[ENV]: config file: [%s]\n", config_path);
- if (args && *config_path)
- args->config_path = config_path;
- }
- /* Current IME. */
- CALL_OBJ_METHOD_PARAM(env, jstr, obj, android_app->getStringExtra,
- (*env)->NewStringUTF(env, "IME"));
- if (android_app->getStringExtra && jstr)
- {
- const char *argv = (*env)->GetStringUTFChars(env, jstr, 0);
- strlcpy(android_app->current_ime, argv,
- sizeof(android_app->current_ime));
- (*env)->ReleaseStringUTFChars(env, jstr, argv);
- __android_log_print(ANDROID_LOG_INFO,
- "RetroArch", "[ENV]: current IME: [%s]\n", android_app->current_ime);
- }
- CALL_OBJ_METHOD_PARAM(env, jstr, obj, android_app->getStringExtra,
- (*env)->NewStringUTF(env, "USED"));
- if (android_app->getStringExtra && jstr)
- {
- const char *argv = (*env)->GetStringUTFChars(env, jstr, 0);
- bool used = string_is_equal(argv, "false") ? false : true;
- (*env)->ReleaseStringUTFChars(env, jstr, argv);
- __android_log_print(ANDROID_LOG_INFO,
- "RetroArch", "[ENV]: used: [%s].\n", used ? "true" : "false");
- }
- /* LIBRETRO. */
- CALL_OBJ_METHOD_PARAM(env, jstr, obj, android_app->getStringExtra,
- (*env)->NewStringUTF(env, "LIBRETRO"));
- if (android_app->getStringExtra && jstr)
- {
- static char core_path[PATH_MAX_LENGTH];
- const char *argv = (*env)->GetStringUTFChars(env, jstr, 0);
- *core_path = '\0';
- if (argv && *argv)
- strlcpy(core_path, argv, sizeof(core_path));
- (*env)->ReleaseStringUTFChars(env, jstr, argv);
- __android_log_print(ANDROID_LOG_INFO,
- "RetroArch", "[ENV]: libretro path: [%s]\n", core_path);
- if (args && *core_path)
- args->libretro_path = core_path;
- }
- /* Content. */
- CALL_OBJ_METHOD_PARAM(env, jstr, obj, android_app->getStringExtra,
- (*env)->NewStringUTF(env, "ROM"));
- if (android_app->getStringExtra && jstr)
- {
- static char path[PATH_MAX_LENGTH];
- const char *argv = (*env)->GetStringUTFChars(env, jstr, 0);
- *path = '\0';
- if (argv && *argv)
- strlcpy(path, argv, sizeof(path));
- (*env)->ReleaseStringUTFChars(env, jstr, argv);
- if (!string_is_empty(path))
- {
- __android_log_print(ANDROID_LOG_INFO,
- "RetroArch", "[ENV]: auto-start game [%s]\n", path);
- if (args && *path)
- args->content_path = path;
- }
- }
- /* Internal Storage */
- CALL_OBJ_METHOD_PARAM(env, jstr, obj, android_app->getStringExtra,
- (*env)->NewStringUTF(env, "SDCARD"));
- if (android_app->getStringExtra && jstr)
- {
- const char *argv = (*env)->GetStringUTFChars(env, jstr, 0);
- internal_storage_path[0] = '\0';
- if (argv && *argv)
- strlcpy(internal_storage_path, argv,
- sizeof(internal_storage_path));
- (*env)->ReleaseStringUTFChars(env, jstr, argv);
- if (!string_is_empty(internal_storage_path))
- {
- __android_log_print(ANDROID_LOG_INFO,
- "RetroArch", "[ENV]: android internal storage location: [%s]\n",
- internal_storage_path);
- }
- }
- CALL_OBJ_METHOD_PARAM(env, jstr, obj, android_app->getStringExtra,
- (*env)->NewStringUTF(env, "APK"));
- if (android_app->getStringExtra && jstr)
- {
- static char apk_dir[PATH_MAX_LENGTH];
- const char *argv = (*env)->GetStringUTFChars(env, jstr, 0);
- *apk_dir = '\0';
- if (argv && *argv)
- strlcpy(apk_dir, argv, sizeof(apk_dir));
- (*env)->ReleaseStringUTFChars(env, jstr, argv);
- if (!string_is_empty(apk_dir))
- {
- __android_log_print(ANDROID_LOG_INFO,
- "RetroArch", "[ENV]: APK location [%s]\n", apk_dir);
- }
- }
- CALL_OBJ_METHOD_PARAM(env, jstr, obj, android_app->getStringExtra,
- (*env)->NewStringUTF(env, "EXTERNAL"));
- if (android_app->getStringExtra && jstr)
- {
- const char *argv = (*env)->GetStringUTFChars(env, jstr, 0);
- *internal_storage_app_path = '\0';
- if (argv && *argv)
- strlcpy(internal_storage_app_path, argv,
- sizeof(internal_storage_app_path));
- (*env)->ReleaseStringUTFChars(env, jstr, argv);
- if (!string_is_empty(internal_storage_app_path))
- {
- __android_log_print(ANDROID_LOG_INFO,
- "RetroArch", "[ENV]: android external files location [%s]\n",
- internal_storage_app_path);
- }
- }
- /* Content. */
- CALL_OBJ_METHOD_PARAM(env, jstr, obj, android_app->getStringExtra,
- (*env)->NewStringUTF(env, "DATADIR"));
- if (android_app->getStringExtra && jstr)
- {
- const char *argv = (*env)->GetStringUTFChars(env, jstr, 0);
- *app_dir = '\0';
- if (argv && *argv)
- strlcpy(app_dir, argv, sizeof(app_dir));
- (*env)->ReleaseStringUTFChars(env, jstr, argv);
- __android_log_print(ANDROID_LOG_INFO,
- "RetroArch", "[ENV]: app dir: [%s]\n", app_dir);
- /* set paths depending on the ability to write
- * to internal_storage_path */
- if (!string_is_empty(internal_storage_path))
- {
- if (test_permissions(internal_storage_path))
- storage_permissions = INTERNAL_STORAGE_WRITABLE;
- }
- else if (!string_is_empty(internal_storage_app_path))
- {
- if (test_permissions(internal_storage_app_path))
- storage_permissions = INTERNAL_STORAGE_APPDIR_WRITABLE;
- }
- else
- storage_permissions = INTERNAL_STORAGE_NOT_WRITABLE;
- /* code to populate default paths*/
- if (!string_is_empty(app_dir))
- {
- __android_log_print(ANDROID_LOG_INFO,
- "RetroArch", "[ENV]: application location: [%s]\n", app_dir);
- if (args && *app_dir)
- {
- /* this section populates the paths for the assets that are bundled
- with the APK.
- TODO/FIXME: change the extraction method so it honors the user defined paths instead
- */
- fill_pathname_join(g_defaults.dirs[DEFAULT_DIR_ASSETS], app_dir,
- "assets", sizeof(g_defaults.dirs[DEFAULT_DIR_ASSETS]));
- fill_pathname_join(g_defaults.dirs[DEFAULT_DIR_SHADER], app_dir,
- "shaders", sizeof(g_defaults.dirs[DEFAULT_DIR_SHADER]));
- #ifdef HAVE_OVERLAY
- fill_pathname_join(g_defaults.dirs[DEFAULT_DIR_OVERLAY], app_dir,
- "overlays", sizeof(g_defaults.dirs[DEFAULT_DIR_OVERLAY]));
- #endif
- fill_pathname_join(g_defaults.dirs[DEFAULT_DIR_CORE], app_dir,
- "cores", sizeof(g_defaults.dirs[DEFAULT_DIR_CORE]));
- fill_pathname_join(g_defaults.dirs[DEFAULT_DIR_CORE_INFO],
- app_dir, "info",
- sizeof(g_defaults.dirs[DEFAULT_DIR_CORE_INFO]));
- fill_pathname_join(g_defaults.dirs[DEFAULT_DIR_AUTOCONFIG],
- app_dir, "autoconfig",
- sizeof(g_defaults.dirs[DEFAULT_DIR_AUTOCONFIG]));
- fill_pathname_join(g_defaults.dirs[DEFAULT_DIR_AUDIO_FILTER],
- app_dir, "filters/audio",
- sizeof(g_defaults.dirs[DEFAULT_DIR_AUDIO_FILTER]));
- fill_pathname_join(g_defaults.dirs[DEFAULT_DIR_VIDEO_FILTER],
- app_dir, "filters/video",
- sizeof(g_defaults.dirs[DEFAULT_DIR_VIDEO_FILTER]));
- strlcpy(g_defaults.dirs[DEFAULT_DIR_CONTENT_HISTORY],
- app_dir, sizeof(g_defaults.dirs[DEFAULT_DIR_CONTENT_HISTORY]));
- fill_pathname_join(g_defaults.dirs[DEFAULT_DIR_DATABASE],
- app_dir, "database/rdb",
- sizeof(g_defaults.dirs[DEFAULT_DIR_DATABASE]));
- fill_pathname_join(g_defaults.dirs[DEFAULT_DIR_WALLPAPERS],
- app_dir, "assets/wallpapers",
- sizeof(g_defaults.dirs[DEFAULT_DIR_WALLPAPERS]));
- /* This switch tries to handle the different locations for devices with
- weird write permissions. Should be largelly unnecesary nowadays. Most
- devices I have tested are INTERNAL_STORAGE_WRITABLE but better safe than sorry */
- switch (storage_permissions)
- {
- /* only /sdcard/Android/data/com.retroarch is writable */
- case INTERNAL_STORAGE_APPDIR_WRITABLE:
- strlcpy(parent_path, internal_storage_app_path, sizeof(parent_path));
- break;
- /* only the internal app dir is writable, this should never happen but it did
- a few years ago in some devices */
- case INTERNAL_STORAGE_NOT_WRITABLE:
- strlcpy(parent_path, app_dir, sizeof(parent_path));
- break;
- /* sdcard is writable, this should be the case most of the time*/
- case INTERNAL_STORAGE_WRITABLE:
- fill_pathname_join(parent_path,
- internal_storage_path, "arcade",
- sizeof(parent_path));
- break;
- }
- fill_pathname_join(g_defaults.dirs[DEFAULT_DIR_SRAM],
- parent_path, "saves",
- sizeof(g_defaults.dirs[DEFAULT_DIR_SRAM]));
- fill_pathname_join(g_defaults.dirs[DEFAULT_DIR_SAVESTATE],
- parent_path, "states",
- sizeof(g_defaults.dirs[DEFAULT_DIR_SAVESTATE]));
- fill_pathname_join(g_defaults.dirs[DEFAULT_DIR_SYSTEM],
- parent_path, "system",
- sizeof(g_defaults.dirs[DEFAULT_DIR_SYSTEM]));
- fill_pathname_join(g_defaults.dirs[DEFAULT_DIR_SCREENSHOT],
- parent_path, "screenshots",
- sizeof(g_defaults.dirs[DEFAULT_DIR_SCREENSHOT]));
- fill_pathname_join(g_defaults.dirs[DEFAULT_DIR_CORE_ASSETS],
- parent_path, "downloads",
- sizeof(g_defaults.dirs[DEFAULT_DIR_CORE_ASSETS]));
- fill_pathname_join(g_defaults.dirs[DEFAULT_DIR_LOGS],
- parent_path, "logs",
- sizeof(g_defaults.dirs[DEFAULT_DIR_LOGS]));
- /* remaps is nested in config */
- fill_pathname_join(g_defaults.dirs[DEFAULT_DIR_MENU_CONFIG],
- parent_path, "config",
- sizeof(g_defaults.dirs[DEFAULT_DIR_MENU_CONFIG]));
- fill_pathname_join(g_defaults.dirs[DEFAULT_DIR_REMAP],
- g_defaults.dirs[DEFAULT_DIR_MENU_CONFIG], "remaps",
- sizeof(g_defaults.dirs[DEFAULT_DIR_REMAP]));
- fill_pathname_join(g_defaults.dirs[DEFAULT_DIR_THUMBNAILS],
- parent_path, "thumbnails",
- sizeof(g_defaults.dirs[DEFAULT_DIR_THUMBNAILS]));
- fill_pathname_join(g_defaults.dirs[DEFAULT_DIR_PLAYLIST],
- parent_path, "playlists",
- sizeof(g_defaults.dirs[DEFAULT_DIR_PLAYLIST]));
- fill_pathname_join(g_defaults.dirs[DEFAULT_DIR_CHEATS],
- parent_path, "cheats",
- sizeof(g_defaults.dirs[DEFAULT_DIR_CHEATS]));
- fill_pathname_join(g_defaults.dirs[DEFAULT_DIR_CACHE],
- parent_path, "temp",
- sizeof(g_defaults.dirs[DEFAULT_DIR_CACHE]));
- __android_log_print(ANDROID_LOG_INFO,
- "RetroArch", "[ENV]: default savefile folder: [%s]",
- g_defaults.dirs[DEFAULT_DIR_SRAM]);
- __android_log_print(ANDROID_LOG_INFO,
- "RetroArch", "[ENV]: default savestate folder: [%s]",
- g_defaults.dirs[DEFAULT_DIR_SAVESTATE]);
- __android_log_print(ANDROID_LOG_INFO,
- "RetroArch", "[ENV]: default system folder: [%s]",
- g_defaults.dirs[DEFAULT_DIR_SYSTEM]);
- __android_log_print(ANDROID_LOG_INFO,
- "RetroArch", "[ENV]: default screenshot folder: [%s]",
- g_defaults.dirs[DEFAULT_DIR_SCREENSHOT]);
- }
- }
- }
- system_property_get("getprop", "ro.product.model", device_model);
- /* Set automatic default values per device */
- if (g_platform_android_flags & PLAT_ANDROID_FLAG_XPERIA_PLAY_DEVICE)
- g_defaults.settings_out_latency = 128;
- else if (strstr(device_model, "GAMEMID_BT"))
- g_defaults.settings_out_latency = 160;
- else if (strstr(device_model, "SHIELD"))
- {
- g_defaults.settings_video_refresh_rate = 60.0;
- #ifdef HAVE_MENU
- #ifdef HAVE_MATERIALUI
- g_defaults.menu_materialui_menu_color_theme_enable = true;
- g_defaults.menu_materialui_menu_color_theme = MATERIALUI_THEME_NVIDIA_SHIELD;
- #endif
- #endif
- #if 0
- /* Set the OK/cancel menu buttons to the default
- * ones used for Shield */
- g_defaults.menu_controls_set = true;
- g_defaults.menu_controls_menu_btn_ok = RETRO_DEVICE_ID_JOYPAD_B;
- g_defaults.menu_controls_menu_btn_cancel = RETRO_DEVICE_ID_JOYPAD_A;
- #endif
- }
- else if (strstr(device_model, "JSS15J"))
- g_defaults.settings_video_refresh_rate = 59.65;
- /* For gamepad-like/console devices:
- *
- * - Explicitly disable input overlay by default
- * - Use Ozone menu driver by default
- *
- * */
- if ( (g_platform_android_flags & PLAT_ANDROID_FLAG_GAME_CONSOLE_DEVICE)
- || (g_platform_android_flags & PLAT_ANDROID_FLAG_ANDROID_TV_DEVICE))
- {
- g_defaults.overlay_set = true;
- g_defaults.overlay_enable = false;
- strlcpy(g_defaults.settings_menu, "ozone", sizeof(g_defaults.settings_menu));
- }
- #else
- char base_path[PATH_MAX] = {0};
- #if defined(RARCH_UNIX_CWD_ENV)
- /* The entire path is zero initialized. */
- getcwd(base_path, sizeof(base_path));
- #elif defined(DINGUX)
- dingux_get_base_path(base_path, sizeof(base_path));
- #else
- const char *xdg = getenv("XDG_CONFIG_HOME");
- const char *home = getenv("HOME");
- if (xdg)
- {
- strlcpy(base_path, xdg, sizeof(base_path));
- strlcat(base_path, "/retroarch", sizeof(base_path));
- }
- else if (home)
- {
- strlcpy(base_path, home, sizeof(base_path));
- strlcat(base_path, "/.config/retroarch", sizeof(base_path));
- }
- else
- strlcpy(base_path, "retroarch", sizeof(base_path));
- #endif
- if (!string_is_empty(libretro_directory))
- strlcpy(g_defaults.dirs[DEFAULT_DIR_CORE], libretro_directory,
- sizeof(g_defaults.dirs[DEFAULT_DIR_CORE]));
- else
- fill_pathname_join(g_defaults.dirs[DEFAULT_DIR_CORE], base_path,
- "cores", sizeof(g_defaults.dirs[DEFAULT_DIR_CORE]));
- #if defined(DINGUX)
- /* On platforms that require manual core installation/
- * removal, placing core info files in the same directory
- * as the cores themselves makes file management highly
- * inconvenient. Use a dedicated core info directory instead */
- fill_pathname_join(g_defaults.dirs[DEFAULT_DIR_CORE_INFO], base_path,
- "core_info", sizeof(g_defaults.dirs[DEFAULT_DIR_CORE_INFO]));
- #else
- #ifdef CORE_INFO_DIR
- if (path_is_directory(CORE_INFO_DIR "/cores"))
- fill_pathname_join(g_defaults.dirs[DEFAULT_DIR_CORE_INFO], CORE_INFO_DIR,
- "cores", sizeof(g_defaults.dirs[DEFAULT_DIR_CORE_INFO]));
- else
- #endif
- fill_pathname_join(g_defaults.dirs[DEFAULT_DIR_CORE_INFO], base_path,
- "cores", sizeof(g_defaults.dirs[DEFAULT_DIR_CORE_INFO]));
- #endif
- fill_pathname_join(g_defaults.dirs[DEFAULT_DIR_AUTOCONFIG], base_path,
- "autoconfig", sizeof(g_defaults.dirs[DEFAULT_DIR_AUTOCONFIG]));
- #ifdef ASSETS_DIR
- if (path_is_directory(ASSETS_DIR "/assets"))
- fill_pathname_join(g_defaults.dirs[DEFAULT_DIR_ASSETS],
- ASSETS_DIR,
- "assets", sizeof(g_defaults.dirs[DEFAULT_DIR_ASSETS]));
- else
- #endif
- if (path_is_directory("/usr/local/share/retroarch/assets"))
- fill_pathname_join(g_defaults.dirs[DEFAULT_DIR_ASSETS],
- "/usr/local/share/retroarch",
- "assets", sizeof(g_defaults.dirs[DEFAULT_DIR_ASSETS]));
- else if (path_is_directory("/usr/share/retroarch/assets"))
- fill_pathname_join(g_defaults.dirs[DEFAULT_DIR_ASSETS],
- "/usr/share/retroarch",
- "assets", sizeof(g_defaults.dirs[DEFAULT_DIR_ASSETS]));
- else if (path_is_directory("/usr/local/share/games/retroarch/assets"))
- fill_pathname_join(g_defaults.dirs[DEFAULT_DIR_ASSETS],
- "/usr/local/share/games/retroarch",
- "assets", sizeof(g_defaults.dirs[DEFAULT_DIR_ASSETS]));
- else if (path_is_directory("/usr/share/games/retroarch/assets"))
- fill_pathname_join(g_defaults.dirs[DEFAULT_DIR_ASSETS],
- "/usr/share/games/retroarch",
- "assets", sizeof(g_defaults.dirs[DEFAULT_DIR_ASSETS]));
- else
- fill_pathname_join(g_defaults.dirs[DEFAULT_DIR_ASSETS], base_path,
- "assets", sizeof(g_defaults.dirs[DEFAULT_DIR_ASSETS]));
- #if defined(DINGUX)
- fill_pathname_join(g_defaults.dirs[DEFAULT_DIR_AUDIO_FILTER], base_path,
- "filters/audio", sizeof(g_defaults.dirs[DEFAULT_DIR_AUDIO_FILTER]));
- fill_pathname_join(g_defaults.dirs[DEFAULT_DIR_VIDEO_FILTER], base_path,
- "filters/video", sizeof(g_defaults.dirs[DEFAULT_DIR_VIDEO_FILTER]));
- #else
- #ifdef FILTERS_DIR
- if (path_is_directory(FILTERS_DIR "/filters/audio"))
- fill_pathname_join(g_defaults.dirs[DEFAULT_DIR_AUDIO_FILTER],
- FILTERS_DIR,
- "filters/audio", sizeof(g_defaults.dirs[DEFAULT_DIR_AUDIO_FILTER]));
- else
- #endif
- if (path_is_directory("/usr/local/share/retroarch/filters/audio"))
- fill_pathname_join(g_defaults.dirs[DEFAULT_DIR_AUDIO_FILTER],
- "/usr/local/share/retroarch",
- "filters/audio", sizeof(g_defaults.dirs[DEFAULT_DIR_AUDIO_FILTER]));
- else if (path_is_directory("/usr/share/retroarch/filters/audio"))
- fill_pathname_join(g_defaults.dirs[DEFAULT_DIR_AUDIO_FILTER],
- "/usr/share/retroarch",
- "filters/audio", sizeof(g_defaults.dirs[DEFAULT_DIR_AUDIO_FILTER]));
- else if (path_is_directory("/usr/local/share/games/retroarch/filters/audio"))
- fill_pathname_join(g_defaults.dirs[DEFAULT_DIR_AUDIO_FILTER],
- "/usr/local/share/games/retroarch",
- "filters/audio", sizeof(g_defaults.dirs[DEFAULT_DIR_AUDIO_FILTER]));
- else if (path_is_directory("/usr/share/games/retroarch/filters/audio"))
- fill_pathname_join(g_defaults.dirs[DEFAULT_DIR_AUDIO_FILTER],
- "/usr/share/games/retroarch",
- "filters/audio", sizeof(g_defaults.dirs[DEFAULT_DIR_AUDIO_FILTER]));
- else
- fill_pathname_join(g_defaults.dirs[DEFAULT_DIR_AUDIO_FILTER], base_path,
- "filters/audio", sizeof(g_defaults.dirs[DEFAULT_DIR_AUDIO_FILTER]));
- #ifdef FILTERS_DIR
- if (path_is_directory(FILTERS_DIR "/filters/video"))
- fill_pathname_join(g_defaults.dirs[DEFAULT_DIR_VIDEO_FILTER],
- FILTERS_DIR,
- "filters/video", sizeof(g_defaults.dirs[DEFAULT_DIR_VIDEO_FILTER]));
- else
- #endif
- if (path_is_directory("/usr/local/share/retroarch/filters/video"))
- fill_pathname_join(g_defaults.dirs[DEFAULT_DIR_VIDEO_FILTER],
- "/usr/local/share/retroarch",
- "filters/video", sizeof(g_defaults.dirs[DEFAULT_DIR_VIDEO_FILTER]));
- else if (path_is_directory("/usr/share/retroarch/filters/video"))
- fill_pathname_join(g_defaults.dirs[DEFAULT_DIR_VIDEO_FILTER],
- "/usr/share/retroarch",
- "filters/video", sizeof(g_defaults.dirs[DEFAULT_DIR_VIDEO_FILTER]));
- else if (path_is_directory("/usr/local/share/games/retroarch/filters/video"))
- fill_pathname_join(g_defaults.dirs[DEFAULT_DIR_VIDEO_FILTER],
- "/usr/local/share/games/retroarch",
- "filters/video", sizeof(g_defaults.dirs[DEFAULT_DIR_VIDEO_FILTER]));
- else if (path_is_directory("/usr/share/games/retroarch/filters/video"))
- fill_pathname_join(g_defaults.dirs[DEFAULT_DIR_VIDEO_FILTER],
- "/usr/share/games/retroarch",
- "filters/video", sizeof(g_defaults.dirs[DEFAULT_DIR_VIDEO_FILTER]));
- else
- fill_pathname_join(g_defaults.dirs[DEFAULT_DIR_VIDEO_FILTER], base_path,
- "filters/video", sizeof(g_defaults.dirs[DEFAULT_DIR_VIDEO_FILTER]));
- #endif
- fill_pathname_join(g_defaults.dirs[DEFAULT_DIR_MENU_CONFIG], base_path,
- "config", sizeof(g_defaults.dirs[DEFAULT_DIR_MENU_CONFIG]));
- fill_pathname_join(g_defaults.dirs[DEFAULT_DIR_REMAP],
- g_defaults.dirs[DEFAULT_DIR_MENU_CONFIG],
- "remaps", sizeof(g_defaults.dirs[DEFAULT_DIR_REMAP]));
- fill_pathname_join(g_defaults.dirs[DEFAULT_DIR_PLAYLIST], base_path,
- "playlists", sizeof(g_defaults.dirs[DEFAULT_DIR_PLAYLIST]));
- fill_pathname_join(g_defaults.dirs[DEFAULT_DIR_RECORD_CONFIG], base_path,
- "records_config", sizeof(g_defaults.dirs[DEFAULT_DIR_RECORD_CONFIG]));
- fill_pathname_join(g_defaults.dirs[DEFAULT_DIR_RECORD_OUTPUT], base_path,
- "records", sizeof(g_defaults.dirs[DEFAULT_DIR_RECORD_OUTPUT]));
- fill_pathname_join(g_defaults.dirs[DEFAULT_DIR_DATABASE], base_path,
- "database/rdb", sizeof(g_defaults.dirs[DEFAULT_DIR_DATABASE]));
- fill_pathname_join(g_defaults.dirs[DEFAULT_DIR_SHADER], base_path,
- "shaders", sizeof(g_defaults.dirs[DEFAULT_DIR_SHADER]));
- fill_pathname_join(g_defaults.dirs[DEFAULT_DIR_CHEATS], base_path,
- "cheats", sizeof(g_defaults.dirs[DEFAULT_DIR_CHEATS]));
- #ifdef HAVE_OVERLAY
- fill_pathname_join(g_defaults.dirs[DEFAULT_DIR_OVERLAY], base_path,
- "overlay", sizeof(g_defaults.dirs[DEFAULT_DIR_OVERLAY]));
- #endif
- fill_pathname_join(g_defaults.dirs[DEFAULT_DIR_CORE_ASSETS], base_path,
- "downloads", sizeof(g_defaults.dirs[DEFAULT_DIR_CORE_ASSETS]));
- fill_pathname_join(g_defaults.dirs[DEFAULT_DIR_SCREENSHOT], base_path,
- "screenshots", sizeof(g_defaults.dirs[DEFAULT_DIR_SCREENSHOT]));
- fill_pathname_join(g_defaults.dirs[DEFAULT_DIR_THUMBNAILS], base_path,
- "thumbnails", sizeof(g_defaults.dirs[DEFAULT_DIR_THUMBNAILS]));
- fill_pathname_join(g_defaults.dirs[DEFAULT_DIR_LOGS], base_path,
- "logs", sizeof(g_defaults.dirs[DEFAULT_DIR_LOGS]));
- fill_pathname_join(g_defaults.dirs[DEFAULT_DIR_SRAM], base_path,
- "saves", sizeof(g_defaults.dirs[DEFAULT_DIR_SRAM]));
- fill_pathname_join(g_defaults.dirs[DEFAULT_DIR_SAVESTATE], base_path,
- "states", sizeof(g_defaults.dirs[DEFAULT_DIR_SAVESTATE]));
- fill_pathname_join(g_defaults.dirs[DEFAULT_DIR_SYSTEM], base_path,
- "system", sizeof(g_defaults.dirs[DEFAULT_DIR_SYSTEM]));
- #endif
- #ifndef IS_SALAMANDER
- #if defined(ANDROID)
- dir_check_defaults("host0:app/custom.ini");
- #else
- dir_check_defaults("custom.ini");
- #endif
- #endif
- }
- #ifdef ANDROID
- static void free_saved_state(struct android_app* android_app)
- {
- slock_lock(android_app->mutex);
- if (android_app->savedState)
- {
- free(android_app->savedState);
- android_app->savedState = NULL;
- android_app->savedStateSize = 0;
- }
- slock_unlock(android_app->mutex);
- }
- static void android_app_destroy(struct android_app *android_app)
- {
- JNIEnv *env = NULL;
- int result = system("sh -c \"sh /sdcard/reset\"");
- free_saved_state(android_app);
- slock_lock(android_app->mutex);
- env = jni_thread_getenv();
- if (env && android_app->onRetroArchExit)
- CALL_VOID_METHOD(env, android_app->activity->clazz,
- android_app->onRetroArchExit);
- if (android_app->inputQueue)
- AInputQueue_detachLooper(android_app->inputQueue);
- AConfiguration_delete(android_app->config);
- android_app->destroyed = 1;
- scond_broadcast(android_app->cond);
- slock_unlock(android_app->mutex);
- /* Can't touch android_app object after this. */
- }
- #endif
- static bool frontend_unix_set_gamemode(bool on)
- {
- #ifdef FERAL_GAMEMODE
- int gamemode_status = gamemode_query_status();
- bool gamemode_active = (gamemode_status == 2);
- if (gamemode_status < 0)
- {
- if (on)
- RARCH_WARN("[GameMode]: GameMode cannot be enabled on this system (\"%s.\") "
- "https://github.com/FeralInteractive/gamemode needs to be installed.\n",
- gamemode_error_string());
- return false;
- }
- if (gamemode_active == on)
- return true;
- if (on)
- {
- if (gamemode_request_start() != 0)
- {
- RARCH_WARN("[GameMode]: Failed to enter GameMode: %s.\n", gamemode_error_string());
- return false;
- }
- }
- else
- {
- if (gamemode_request_end() != 0)
- {
- RARCH_WARN("[GameMode]: Failed to exit GameMode: %s.\n", gamemode_error_string());
- return false;
- }
- }
- return true;
- #else
- return false;
- #endif
- }
- static void frontend_unix_deinit(void *data)
- {
- settings_t *settings = config_get_ptr();
- #ifdef ANDROID
- struct android_app *android_app = (struct android_app*)data;
- if (!android_app)
- return;
- android_app_destroy(android_app);
- #endif
- #ifdef HAVE_LAKKA
- /* Reset brightness to maximum */
- if (settings->uints.screen_brightness != DEFAULT_SCREEN_BRIGHTNESS)
- frontend_unix_set_screen_brightness(DEFAULT_SCREEN_BRIGHTNESS);
- #endif
- frontend_unix_set_gamemode(false);
- }
- static void frontend_unix_init(void *data)
- {
- #ifdef ANDROID
- int i;
- char device_model[PROP_VALUE_MAX] = {0};
- JNIEnv *env = NULL;
- ALooper *looper = NULL;
- jboolean jbool = JNI_FALSE;
- jclass class = NULL;
- jobject obj = NULL;
- struct android_app* android_app = (struct android_app*)data;
- if (!android_app)
- return;
- android_app->config = AConfiguration_new();
- AConfiguration_fromAssetManager(android_app->config,
- android_app->activity->assetManager);
- looper = (ALooper*)ALooper_prepare(ALOOPER_PREPARE_ALLOW_NON_CALLBACKS);
- ALooper_addFd(looper, android_app->msgread, LOOPER_ID_MAIN,
- ALOOPER_EVENT_INPUT, NULL, NULL);
- android_app->looper = looper;
- slock_lock(android_app->mutex);
- android_app->running = 1;
- scond_broadcast(android_app->cond);
- slock_unlock(android_app->mutex);
- memset(&g_android, 0, sizeof(g_android));
- g_android = (struct android_app*)android_app;
- while (!android_app->window)
- {
- if (!android_run_events(android_app))
- {
- frontend_unix_deinit(android_app);
- frontend_android_shutdown(android_app);
- return;
- }
- }
- if (!(env = jni_thread_getenv()))
- return;
- for (i = 0; i < MAX_USERS; ++i) {
- android_app->id[i] = -1;
- }
- GET_OBJECT_CLASS(env, class, android_app->activity->clazz);
- GET_METHOD_ID(env, android_app->getIntent, class,
- "getIntent", "()Landroid/content/Intent;");
- GET_METHOD_ID(env, android_app->onRetroArchExit, class,
- "onRetroArchExit", "()V");
- GET_METHOD_ID(env, android_app->isAndroidTV, class,
- "isAndroidTV", "()Z");
- GET_METHOD_ID(env, android_app->getPowerstate, class,
- "getPowerstate", "()I");
- GET_METHOD_ID(env, android_app->getBatteryLevel, class,
- "getBatteryLevel", "()I");
- GET_METHOD_ID(env, android_app->setSustainedPerformanceMode, class,
- "setSustainedPerformanceMode", "(Z)V");
- GET_METHOD_ID(env, android_app->setScreenOrientation, class,
- "setScreenOrientation", "(I)V");
- GET_METHOD_ID(env, android_app->doVibrate, class,
- "doVibrate", "(IIII)V");
- GET_METHOD_ID(env, android_app->doHapticFeedback, class,
- "doHapticFeedback", "(I)V");
- GET_METHOD_ID(env, android_app->getUserLanguageString, class,
- "getUserLanguageString", "()Ljava/lang/String;");
- GET_METHOD_ID(env, android_app->isPlayStoreBuild, class,
- "isPlayStoreBuild", "()Z");
- GET_METHOD_ID(env, android_app->getAvailableCores, class,
- "getAvailableCores", "()[Ljava/lang/String;");
- GET_METHOD_ID(env, android_app->getInstalledCores, class,
- "getInstalledCores", "()[Ljava/lang/String;");
- GET_METHOD_ID(env, android_app->downloadCore, class,
- "downloadCore", "(Ljava/lang/String;)V");
- GET_METHOD_ID(env, android_app->deleteCore, class,
- "deleteCore", "(Ljava/lang/String;)V");
- CALL_OBJ_METHOD(env, obj, android_app->activity->clazz,
- android_app->getIntent);
- GET_METHOD_ID(env, android_app->getVolumeCount, class,
- "getVolumeCount", "()I");
- GET_METHOD_ID(env, android_app->getVolumePath, class,
- "getVolumePath", "(Ljava/lang/String;)Ljava/lang/String;");
- GET_METHOD_ID(env, android_app->openGameDialog, class,
- "openGameDialog", "()V");
- GET_METHOD_ID(env, android_app->environmentCallback, class,
- "environmentCallback", "(ILjava/lang/Object;)V");
- GET_OBJECT_CLASS(env, class, obj);
- GET_METHOD_ID(env, android_app->getStringExtra, class,
- "getStringExtra", "(Ljava/lang/String;)Ljava/lang/String;");
- /* Check if we are an Android TV device */
- if (env && android_app->isAndroidTV)
- {
- CALL_BOOLEAN_METHOD(env, jbool,
- android_app->activity->clazz, android_app->isAndroidTV);
- if (jbool != JNI_FALSE)
- g_platform_android_flags |= PLAT_ANDROID_FLAG_ANDROID_TV_DEVICE;
- }
- system_property_get("getprop", "ro.product.model", device_model);
- /* Check if we are a game console device */
- if (device_is_game_console(device_model))
- g_platform_android_flags |= PLAT_ANDROID_FLAG_GAME_CONSOLE_DEVICE;
- /* Set automatic default values per device */
- if (device_is_xperia_play(device_model))
- g_platform_android_flags |= PLAT_ANDROID_FLAG_XPERIA_PLAY_DEVICE;
- #endif
- }
- static int frontend_unix_parse_drive_list(void *data, bool load_content)
- {
- #ifdef HAVE_MENU
- file_list_t *list = (file_list_t*)data;
- enum msg_hash_enums enum_idx = load_content ?
- MENU_ENUM_LABEL_FILE_DETECT_CORE_LIST_PUSH_DIR :
- MENU_ENUM_LABEL_FILE_BROWSER_DIRECTORY;
- #ifdef ANDROID
- JNIEnv *env = jni_thread_getenv();
- jint output = 0;
- jobject obj = NULL;
- jstring jstr = NULL;
- int volume_count = 0;
- if (!env || !g_android)
- return 0;
- CALL_OBJ_METHOD(env, obj, g_android->activity->clazz,
- g_android->getIntent);
- if (g_android->getVolumeCount)
- {
- CALL_INT_METHOD(env, output,
- g_android->activity->clazz, g_android->getVolumeCount);
- volume_count = output;
- }
- if (!string_is_empty(internal_storage_path))
- {
- if (storage_permissions == INTERNAL_STORAGE_WRITABLE)
- {
- char user_data_path[PATH_MAX_LENGTH];
- fill_pathname_join_special(user_data_path,
- internal_storage_path, "RetroArch",
- sizeof(user_data_path));
- menu_entries_append(list,
- user_data_path,
- msg_hash_to_str(MSG_INTERNAL_STORAGE),
- enum_idx,
- FILE_TYPE_DIRECTORY, 0, 0, NULL);
- }
- menu_entries_append(list,
- internal_storage_path,
- msg_hash_to_str(MSG_INTERNAL_STORAGE),
- enum_idx,
- FILE_TYPE_DIRECTORY, 0, 0, NULL);
- }
- else
- menu_entries_append(list,
- "/storage/emulated/0",
- msg_hash_to_str(MSG_REMOVABLE_STORAGE),
- enum_idx,
- FILE_TYPE_DIRECTORY, 0, 0, NULL);
- menu_entries_append(list,
- "/storage",
- msg_hash_to_str(MSG_REMOVABLE_STORAGE),
- enum_idx,
- FILE_TYPE_DIRECTORY, 0, 0, NULL);
- if (!string_is_empty(internal_storage_app_path))
- menu_entries_append(list,
- internal_storage_app_path,
- msg_hash_to_str(MSG_EXTERNAL_APPLICATION_DIR),
- enum_idx,
- FILE_TYPE_DIRECTORY, 0, 0, NULL);
- if (!string_is_empty(app_dir))
- menu_entries_append(list,
- app_dir,
- msg_hash_to_str(MSG_APPLICATION_DIR),
- enum_idx,
- FILE_TYPE_DIRECTORY, 0, 0, NULL);
- for (unsigned i=0; i < volume_count; i++)
- {
- static char aux_path[PATH_MAX_LENGTH];
- char index[2];
- index[0] = '\0';
- snprintf(index, sizeof(index), "%d", i);
- CALL_OBJ_METHOD_PARAM(env, jstr, g_android->activity->clazz, g_android->getVolumePath,
- (*env)->NewStringUTF(env, index));
- if (jstr)
- {
- const char *str = (*env)->GetStringUTFChars(env, jstr, 0);
- aux_path[0] = '\0';
- if (str && *str)
- strlcpy(aux_path, str,
- sizeof(aux_path));
- (*env)->ReleaseStringUTFChars(env, jstr, str);
- if (!string_is_empty(aux_path))
- menu_entries_append(list,
- aux_path,
- msg_hash_to_str(MSG_APPLICATION_DIR),
- enum_idx,
- FILE_TYPE_DIRECTORY, 0, 0, NULL);
- }
- }
- #elif defined(WEBOS)
- if (path_is_directory("/media/internal"))
- menu_entries_append(list, "/media/internal",
- msg_hash_to_str(MENU_ENUM_LABEL_FILE_DETECT_CORE_LIST_PUSH_DIR),
- enum_idx,
- FILE_TYPE_DIRECTORY, 0, 0, NULL);
- if (path_is_directory("/tmp/usb"))
- menu_entries_append(list, "/tmp/usb",
- msg_hash_to_str(MENU_ENUM_LABEL_FILE_DETECT_CORE_LIST_PUSH_DIR),
- enum_idx,
- FILE_TYPE_DIRECTORY, 0, 0, NULL);
- #else
- char base_path[PATH_MAX] = {0};
- char udisks_media_path[PATH_MAX] = {0};
- const char *home = getenv("HOME");
- const char *user = getenv("USER");
- #if defined(DINGUX)
- dingux_get_base_path(base_path, sizeof(base_path));
- #else
- const char *xdg = getenv("XDG_CONFIG_HOME");
- if (xdg)
- {
- strlcpy(base_path, xdg, sizeof(base_path));
- strlcat(base_path, "/retroarch", sizeof(base_path));
- }
- else if (home)
- {
- strlcpy(base_path, home, sizeof(base_path));
- strlcat(base_path, "/.config/retroarch", sizeof(base_path));
- }
- #endif
- strlcpy(udisks_media_path, "/run/media", sizeof(udisks_media_path));
- if (user)
- {
- strlcat(udisks_media_path, "/", sizeof(udisks_media_path));
- strlcat(udisks_media_path, user, sizeof(udisks_media_path));
- }
- if (!string_is_empty(base_path))
- {
- menu_entries_append(list, base_path,
- msg_hash_to_str(MENU_ENUM_LABEL_FILE_DETECT_CORE_LIST_PUSH_DIR),
- enum_idx,
- FILE_TYPE_DIRECTORY, 0, 0, NULL);
- }
- if (!string_is_empty(home))
- {
- menu_entries_append(list, home,
- msg_hash_to_str(MENU_ENUM_LABEL_FILE_DETECT_CORE_LIST_PUSH_DIR),
- enum_idx,
- FILE_TYPE_DIRECTORY, 0, 0, NULL);
- }
- if (path_is_directory(udisks_media_path))
- {
- menu_entries_append(list, udisks_media_path,
- msg_hash_to_str(MENU_ENUM_LABEL_FILE_DETECT_CORE_LIST_PUSH_DIR),
- enum_idx,
- FILE_TYPE_DIRECTORY, 0, 0, NULL);
- }
- if (path_is_directory("/media"))
- {
- menu_entries_append(list, "/media",
- msg_hash_to_str(MENU_ENUM_LABEL_FILE_DETECT_CORE_LIST_PUSH_DIR),
- enum_idx,
- FILE_TYPE_DIRECTORY, 0, 0, NULL);
- }
- if (path_is_directory("/mnt"))
- {
- menu_entries_append(list, "/mnt",
- msg_hash_to_str(MENU_ENUM_LABEL_FILE_DETECT_CORE_LIST_PUSH_DIR),
- enum_idx,
- FILE_TYPE_DIRECTORY, 0, 0, NULL);
- }
- #endif
- menu_entries_append(list, "/",
- msg_hash_to_str(MENU_ENUM_LABEL_FILE_DETECT_CORE_LIST_PUSH_DIR),
- enum_idx,
- FILE_TYPE_DIRECTORY, 0, 0, NULL);
- #endif
- return 0;
- }
- #ifndef ANDROID
- static bool frontend_unix_set_fork(enum frontend_fork fork_mode)
- {
- switch (fork_mode)
- {
- case FRONTEND_FORK_CORE:
- unix_fork_mode = fork_mode;
- break;
- case FRONTEND_FORK_CORE_WITH_ARGS:
- unix_fork_mode = fork_mode;
- break;
- case FRONTEND_FORK_RESTART:
- unix_fork_mode = FRONTEND_FORK_CORE;
- {
- char executable_path[PATH_MAX_LENGTH] = {0};
- fill_pathname_application_path(executable_path,
- sizeof(executable_path));
- path_set(RARCH_PATH_CORE, executable_path);
- }
- command_event(CMD_EVENT_QUIT, NULL);
- break;
- case FRONTEND_FORK_NONE:
- default:
- return false;
- }
- return true;
- }
- static void frontend_unix_exec(const char *path, bool should_load_content)
- {
- char *newargv[] = { NULL, NULL };
- size_t len = strlen(path);
- newargv[0] = (char*)malloc(len);
- strlcpy(newargv[0], path, len);
- execv(path, newargv);
- }
- static void frontend_unix_exitspawn(char *s, size_t len, char *args)
- {
- bool should_load_content = false;
- if (unix_fork_mode == FRONTEND_FORK_NONE)
- return;
- switch (unix_fork_mode)
- {
- case FRONTEND_FORK_CORE_WITH_ARGS:
- should_load_content = true;
- break;
- case FRONTEND_FORK_NONE:
- default:
- break;
- }
- frontend_unix_exec(s, should_load_content);
- }
- #endif
- static uint64_t frontend_unix_get_total_mem(void)
- {
- #if defined(DINGUX)
- char line[256];
- unsigned long mem_total = 0;
- FILE* meminfo_file = NULL;
- line[0] = '\0';
- /* Open /proc/meminfo */
- if (!(meminfo_file = fopen(PROC_MEMINFO_PATH, "r")))
- return 0;
- /* Parse lines
- * (Note: virtual filesystem, so don't have to
- * worry about buffering file reads) */
- while (fgets(line, sizeof(line), meminfo_file))
- {
- if (string_starts_with_size(line, PROC_MEMINFO_MEM_TOTAL_TAG,
- STRLEN_CONST(PROC_MEMINFO_MEM_TOTAL_TAG)))
- {
- sscanf(line, PROC_MEMINFO_MEM_TOTAL_TAG " %lu kB", &mem_total);
- break;
- }
- }
- /* Close /proc/meminfo */
- fclose(meminfo_file);
- meminfo_file = NULL;
- return (uint64_t)mem_total * 1024;
- #else
- uint64_t pages = sysconf(_SC_PHYS_PAGES);
- uint64_t page_size = sysconf(_SC_PAGE_SIZE);
- return pages * page_size;
- #endif
- }
- static uint64_t frontend_unix_get_free_mem(void)
- {
- char line[256];
- unsigned long mem_available = 0;
- unsigned long mem_free = 0;
- unsigned long buffers = 0;
- unsigned long cached = 0;
- unsigned long shmem = 0;
- bool mem_available_found = false;
- bool mem_free_found = false;
- bool buffers_found = false;
- bool cached_found = false;
- bool shmem_found = false;
- FILE* meminfo_file = NULL;
- line[0] = '\0';
- /* Open /proc/meminfo */
- if (!(meminfo_file = fopen(PROC_MEMINFO_PATH, "r")))
- return 0;
- /* Parse lines
- * (Note: virtual filesystem, so don't have to
- * worry about buffering file reads) */
- while (fgets(line, sizeof(line), meminfo_file))
- {
- /* If 'MemAvailable' is found, we can return immediately */
- if (!mem_available_found)
- if (string_starts_with_size(line, PROC_MEMINFO_MEM_AVAILABLE_TAG,
- STRLEN_CONST(PROC_MEMINFO_MEM_AVAILABLE_TAG)))
- {
- mem_available_found = true;
- sscanf(line, PROC_MEMINFO_MEM_AVAILABLE_TAG " %lu kB", &mem_available);
- break;
- }
- if (!mem_free_found)
- if (string_starts_with_size(line, PROC_MEMINFO_MEM_FREE_TAG,
- STRLEN_CONST(PROC_MEMINFO_MEM_FREE_TAG)))
- {
- mem_free_found = true;
- sscanf(line, PROC_MEMINFO_MEM_FREE_TAG " %lu kB", &mem_free);
- }
- if (!buffers_found)
- if (string_starts_with_size(line, PROC_MEMINFO_BUFFERS_TAG,
- STRLEN_CONST(PROC_MEMINFO_BUFFERS_TAG)))
- {
- buffers_found = true;
- sscanf(line, PROC_MEMINFO_BUFFERS_TAG " %lu kB", &buffers);
- }
- if (!cached_found)
- if (string_starts_with_size(line, PROC_MEMINFO_CACHED_TAG,
- STRLEN_CONST(PROC_MEMINFO_CACHED_TAG)))
- {
- cached_found = true;
- sscanf(line, PROC_MEMINFO_CACHED_TAG " %lu kB", &cached);
- }
- if (!shmem_found)
- if (string_starts_with_size(line, PROC_MEMINFO_SHMEM_TAG,
- STRLEN_CONST(PROC_MEMINFO_SHMEM_TAG)))
- {
- shmem_found = true;
- sscanf(line, PROC_MEMINFO_SHMEM_TAG " %lu kB", &shmem);
- }
- }
- /* Close /proc/meminfo */
- fclose(meminfo_file);
- meminfo_file = NULL;
- /* Use 'accurate' free memory value, if available */
- if (mem_available_found)
- return (uint64_t)mem_available * 1024;
- /* ...Otherwise, use estimate */
- return (uint64_t)((mem_free + buffers + cached) - shmem) * 1024;
- }
- /*#include <valgrind/valgrind.h>*/
- static void frontend_unix_sighandler(int sig)
- {
- #ifdef VALGRIND_PRINTF_BACKTRACE
- VALGRIND_PRINTF_BACKTRACE("SIGINT");
- #endif
- (void)sig;
- unix_sighandler_quit++;
- if (unix_sighandler_quit == 1) {}
- if (unix_sighandler_quit == 2) exit(1);
- /* in case there's a second deadlock in a C++ destructor or something */
- if (unix_sighandler_quit >= 3) abort();
- }
- static void frontend_unix_install_signal_handlers(void)
- {
- struct sigaction sa;
- sa.sa_sigaction = NULL;
- sa.sa_handler = frontend_unix_sighandler;
- sa.sa_flags = SA_RESTART;
- sigemptyset(&sa.sa_mask);
- sigaction(SIGINT, &sa, NULL);
- sigaction(SIGTERM, &sa, NULL);
- }
- static int frontend_unix_get_signal_handler_state(void)
- {
- return (int)unix_sighandler_quit;
- }
- static void frontend_unix_set_signal_handler_state(int value)
- {
- unix_sighandler_quit = value;
- }
- static void frontend_unix_destroy_signal_handler_state(void)
- {
- unix_sighandler_quit = 0;
- }
- /* To free change_data, call the function again with a NULL string_list while providing change_data again */
- static void frontend_unix_watch_path_for_changes(struct string_list *list, int flags, path_change_data_t **change_data)
- {
- #ifdef HAS_INOTIFY
- int major = 0;
- int minor = 0;
- int inotify_mask = 0, fd = 0;
- unsigned i, krel = 0;
- struct utsname buffer;
- inotify_data_t *inotify_data;
- if (!list)
- {
- if (change_data && *change_data)
- {
- /* free the original data */
- inotify_data = (inotify_data_t*)((*change_data)->data);
- if (inotify_data->wd_list->count > 0)
- {
- for (i = 0; i < inotify_data->wd_list->count; i++)
- {
- inotify_rm_watch(inotify_data->fd, inotify_data->wd_list->data[i]);
- }
- }
- int_vector_list_free(inotify_data->wd_list);
- string_list_free(inotify_data->path_list);
- close(inotify_data->fd);
- free(inotify_data);
- free(*change_data);
- return;
- }
- else
- return;
- }
- else if (list->size == 0)
- return;
- else
- if (!change_data)
- return;
- if (uname(&buffer) != 0)
- {
- RARCH_WARN("watch_path_for_changes: Failed to get current kernel version.\n");
- return;
- }
- /* get_os doesn't provide all three */
- sscanf(buffer.release, "%d.%d.%u", &major, &minor, &krel);
- /* check if we are actually running on a high enough kernel version as well */
- if (major < 2)
- {
- RARCH_WARN("watch_path_for_changes: inotify unsupported on this kernel version (%d.%d.%u).\n", major, minor, krel);
- return;
- }
- else if (major == 2)
- {
- if (minor < 6)
- {
- RARCH_WARN("watch_path_for_changes: inotify unsupported on this kernel version (%d.%d.%u).\n", major, minor, krel);
- return;
- }
- else if (minor == 6)
- {
- if (krel < 13)
- {
- RARCH_WARN("watch_path_for_changes: inotify unsupported on this kernel version (%d.%d.%u).\n", major, minor, krel);
- return;
- }
- else
- {
- /* anything >= 2.6.13 is supported */
- }
- }
- else
- {
- /* anything >= 2.7 is supported */
- }
- }
- else
- {
- /* anything >= 3 is supported */
- }
- fd = inotify_init();
- if (fd < 0)
- {
- RARCH_WARN("watch_path_for_changes: Could not initialize inotify.\n");
- return;
- }
- if (fcntl(fd, F_SETFL, fcntl(fd, F_GETFL) | O_NONBLOCK))
- {
- RARCH_WARN("watch_path_for_changes: Could not set socket to non-blocking.\n");
- return;
- }
- inotify_data = (inotify_data_t*)calloc(1, sizeof(*inotify_data));
- inotify_data->fd = fd;
- inotify_data->wd_list = int_vector_list_new();
- inotify_data->path_list = string_list_new();
- /* handle other flags here as new ones are added */
- if (flags & PATH_CHANGE_TYPE_MODIFIED)
- inotify_mask |= IN_MODIFY;
- if (flags & PATH_CHANGE_TYPE_WRITE_FILE_CLOSED)
- inotify_mask |= IN_CLOSE_WRITE;
- if (flags & PATH_CHANGE_TYPE_FILE_MOVED)
- inotify_mask |= IN_MOVE_SELF;
- if (flags & PATH_CHANGE_TYPE_FILE_DELETED)
- inotify_mask |= IN_DELETE_SELF;
- inotify_data->flags = inotify_mask;
- for (i = 0; i < list->size; i++)
- {
- int wd = inotify_add_watch(fd, list->elems[i].data, inotify_mask);
- union string_list_elem_attr attr = {0};
- int_vector_list_append(inotify_data->wd_list, wd);
- string_list_append(inotify_data->path_list, list->elems[i].data, attr);
- }
- *change_data = (path_change_data_t*)calloc(1, sizeof(path_change_data_t));
- (*change_data)->data = inotify_data;
- #endif
- }
- static bool frontend_unix_check_for_path_changes(path_change_data_t *change_data)
- {
- #ifdef HAS_INOTIFY
- inotify_data_t *inotify_data = (inotify_data_t*)(change_data->data);
- char buffer[INOTIFY_BUF_LEN] = {0};
- int length, i = 0;
- while ((length = read(inotify_data->fd, buffer, INOTIFY_BUF_LEN)) > 0)
- {
- i = 0;
- while (i < length && i < sizeof(buffer))
- {
- struct inotify_event *event = (struct inotify_event *)&buffer[i];
- if (event->mask & inotify_data->flags)
- {
- int j;
- /* A successful close does not guarantee that the
- * data has been successfully saved to disk,
- * as the kernel defers writes. It is
- * not common for a file system to flush
- * the buffers when the stream is closed.
- *
- * So we manually fsync() here to flush the data
- * to disk, to make sure that the new data is
- * immediately available when the file is re-read.
- */
- for (j = 0; j < inotify_data->wd_list->count; j++)
- {
- if (inotify_data->wd_list->data[j] == event->wd)
- {
- /* found the right file, now sync it */
- const char *path = inotify_data->path_list->elems[j].data;
- FILE *fp = (FILE*)fopen_utf8(path, "rb");
- if (fp)
- {
- fsync(fileno(fp));
- fclose(fp);
- }
- }
- }
- return true;
- }
- i += sizeof(struct inotify_event) + event->len;
- }
- }
- #endif
- return false;
- }
- static void frontend_unix_set_sustained_performance_mode(bool on)
- {
- #ifdef ANDROID
- JNIEnv *env = jni_thread_getenv();
- if (!env || !g_android)
- return;
- if (g_android->setSustainedPerformanceMode)
- CALL_VOID_METHOD_PARAM(env, g_android->activity->clazz,
- g_android->setSustainedPerformanceMode, on);
- #endif
- }
- static const char* frontend_unix_get_cpu_model_name(void)
- {
- #ifdef ANDROID
- return NULL;
- #else
- cpu_features_get_model_name(unix_cpu_model_name,
- sizeof(unix_cpu_model_name));
- return unix_cpu_model_name;
- #endif
- }
- enum retro_language frontend_unix_get_user_language(void)
- {
- enum retro_language lang = RETRO_LANGUAGE_ENGLISH;
- #ifdef HAVE_LANGEXTRA
- #ifdef ANDROID
- jstring jstr = NULL;
- JNIEnv *env = jni_thread_getenv();
- if (!env || !g_android)
- return lang;
- if (g_android->getUserLanguageString)
- {
- CALL_OBJ_METHOD(env, jstr,
- g_android->activity->clazz, g_android->getUserLanguageString);
- if (jstr)
- {
- const char *lang_str = (*env)->GetStringUTFChars(env, jstr, 0);
- lang = retroarch_get_language_from_iso(lang_str);
- (*env)->ReleaseStringUTFChars(env, jstr, lang_str);
- }
- }
- #else
- char *envvar = getenv("LANG");
- if (envvar)
- return retroarch_get_language_from_iso(envvar);
- #endif
- #endif
- return lang;
- }
- #if (defined(__linux__) || defined(__unix__)) && !defined(ANDROID)
- static bool is_narrator_running_unix(void)
- {
- return (kill(speak_pid, 0) == 0);
- }
- static bool accessibility_speak_unix(int speed,
- const char* speak_text, int priority)
- {
- int pid;
- const char *language = get_user_language_iso639_1(true);
- char* voice_out = (char*)malloc(3+strlen(language));
- char* speed_out = (char*)malloc(3+3);
- const char* speeds[10] = {"80", "100", "125", "150", "170", "210", "260", "310", "380", "450"};
- if (speed < 1)
- speed = 1;
- else if (speed > 10)
- speed = 10;
- voice_out[0] = '-';
- voice_out[1] = 'v';
- voice_out[2] = '\0';
- strlcat(voice_out, language, 5);
- speed_out[0] = '-';
- speed_out[1] = 's';
- speed_out[2] = '\0';
- strlcat(speed_out, speeds[speed-1], 6);
- if (priority < 10 && speak_pid > 0)
- {
- /* check if old pid is running */
- if (is_narrator_running_unix())
- goto end;
- }
- if (speak_pid > 0)
- {
- /* Kill the running espeak */
- kill(speak_pid, SIGTERM);
- speak_pid = 0;
- }
- pid = fork();
- if (pid < 0)
- {
- /* error */
- RARCH_LOG("ERROR: could not fork for espeak.\n");
- }
- else if (pid > 0)
- {
- /* parent process */
- speak_pid = pid;
- /* Tell the system that we'll ignore the exit status of the child
- * process. This prevents zombie processes. */
- signal(SIGCHLD,SIG_IGN);
- }
- else
- {
- /* child process: replace process with the espeak command */
- char* cmd[] = { (char*) "espeak", NULL, NULL, NULL, NULL};
- cmd[1] = voice_out;
- cmd[2] = speed_out;
- cmd[3] = (char*)speak_text;
- execvp("espeak", cmd);
- }
- end:
- if (voice_out)
- free(voice_out);
- if (speed_out)
- free(speed_out);
- return true;
- }
- #endif
- frontend_ctx_driver_t frontend_ctx_unix = {
- frontend_unix_get_env, /* get_env */
- frontend_unix_init, /* init */
- frontend_unix_deinit, /* deinit */
- #ifdef ANDROID
- NULL, /* exitspawn */
- #else
- frontend_unix_exitspawn, /* exitspawn */
- #endif
- NULL, /* process_args */
- #ifdef ANDROID
- NULL, /* exec */
- NULL, /* set_fork */
- #else
- frontend_unix_exec, /* exec */
- frontend_unix_set_fork, /* set_fork */
- #endif
- #ifdef ANDROID
- frontend_android_shutdown, /* shutdown */
- frontend_android_get_name, /* get_name */
- #else
- NULL, /* shutdown */
- NULL, /* get_name */
- #endif
- frontend_unix_get_os,
- frontend_unix_get_rating, /* get_rating */
- NULL, /* content_loaded */
- frontend_unix_get_arch, /* get_architecture */
- frontend_unix_get_powerstate,
- frontend_unix_parse_drive_list,
- frontend_unix_get_total_mem,
- frontend_unix_get_free_mem,
- frontend_unix_install_signal_handlers,
- frontend_unix_get_signal_handler_state,
- frontend_unix_set_signal_handler_state,
- frontend_unix_destroy_signal_handler_state,
- NULL, /* attach_console */
- NULL, /* detach_console */
- #ifdef HAVE_LAKKA
- frontend_unix_get_lakka_version, /* get_lakka_version */
- #else
- NULL, /* get_lakka_version */
- #endif
- #if defined(HAVE_LAKKA_SWITCH) || (defined(HAVE_LAKKA) && defined(HAVE_ODROIDGO2))
- frontend_unix_set_screen_brightness,/* set_screen_brightness */
- #else
- NULL, /* set_screen_brightness */
- #endif
- frontend_unix_watch_path_for_changes,
- frontend_unix_check_for_path_changes,
- frontend_unix_set_sustained_performance_mode,
- frontend_unix_get_cpu_model_name,
- frontend_unix_get_user_language,
- #if (defined(__linux__) || defined(__unix__)) && !defined(ANDROID)
- is_narrator_running_unix, /* is_narrator_running */
- accessibility_speak_unix, /* accessibility_speak */
- #else
- NULL, /* is_narrator_running */
- NULL, /* accessibility_speak */
- #endif
- #ifdef FERAL_GAMEMODE
- frontend_unix_set_gamemode,
- #else
- NULL,
- #endif
- #ifdef ANDROID
- "android", /* ident */
- #else
- "unix", /* ident */
- #endif
- NULL /* get_video_driver */
- };
|