PageRenderTime 148ms CodeModel.GetById 0ms RepoModel.GetById 0ms app.codeStats 0ms

/indra/newview/llappviewerlinux.cpp

https://bitbucket.org/lindenlab/viewer-beta/
C++ | 515 lines | 362 code | 79 blank | 74 comment | 48 complexity | 844b87f36339d98918bd5ed122775dbb MD5 | raw file
Possible License(s): LGPL-2.1
  1. /**
  2. * @file llappviewerlinux.cpp
  3. * @brief The LLAppViewerLinux class definitions
  4. *
  5. * $LicenseInfo:firstyear=2007&license=viewerlgpl$
  6. * Second Life Viewer Source Code
  7. * Copyright (C) 2010, Linden Research, Inc.
  8. *
  9. * This library is free software; you can redistribute it and/or
  10. * modify it under the terms of the GNU Lesser General Public
  11. * License as published by the Free Software Foundation;
  12. * version 2.1 of the License only.
  13. *
  14. * This library is distributed in the hope that it will be useful,
  15. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  16. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  17. * Lesser General Public License for more details.
  18. *
  19. * You should have received a copy of the GNU Lesser General Public
  20. * License along with this library; if not, write to the Free Software
  21. * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
  22. *
  23. * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
  24. * $/LicenseInfo$
  25. */
  26. #include "llviewerprecompiledheaders.h"
  27. #include "llappviewerlinux.h"
  28. #include "llcommandlineparser.h"
  29. #include "lldiriterator.h"
  30. #include "llmemtype.h"
  31. #include "llurldispatcher.h" // SLURL from other app instance
  32. #include "llviewernetwork.h"
  33. #include "llviewercontrol.h"
  34. #include "llwindowsdl.h"
  35. #include "llmd5.h"
  36. #include "llfindlocale.h"
  37. #include <exception>
  38. #if LL_DBUS_ENABLED
  39. # include "llappviewerlinux_api_dbus.h"
  40. // regrettable hacks to give us better runtime compatibility with older systems inside llappviewerlinux_api.h:
  41. #define llg_return_if_fail(COND) do{if (!(COND)) return;}while(0)
  42. #undef g_return_if_fail
  43. #define g_return_if_fail(COND) llg_return_if_fail(COND)
  44. // The generated API
  45. # include "llappviewerlinux_api.h"
  46. #endif
  47. namespace
  48. {
  49. int gArgC = 0;
  50. char **gArgV = NULL;
  51. void (*gOldTerminateHandler)() = NULL;
  52. }
  53. static void exceptionTerminateHandler()
  54. {
  55. // reinstall default terminate() handler in case we re-terminate.
  56. if (gOldTerminateHandler) std::set_terminate(gOldTerminateHandler);
  57. // treat this like a regular viewer crash, with nice stacktrace etc.
  58. LLAppViewer::handleViewerCrash();
  59. // we've probably been killed-off before now, but...
  60. gOldTerminateHandler(); // call old terminate() handler
  61. }
  62. int main( int argc, char **argv )
  63. {
  64. LLMemType mt1(LLMemType::MTYPE_STARTUP);
  65. #if LL_SOLARIS && defined(__sparc)
  66. asm ("ta\t6"); // NOTE: Make sure memory alignment is enforced on SPARC
  67. #endif
  68. gArgC = argc;
  69. gArgV = argv;
  70. LLAppViewer* viewer_app_ptr = new LLAppViewerLinux();
  71. // install unexpected exception handler
  72. gOldTerminateHandler = std::set_terminate(exceptionTerminateHandler);
  73. // install crash handlers
  74. viewer_app_ptr->setErrorHandler(LLAppViewer::handleViewerCrash);
  75. bool ok = viewer_app_ptr->init();
  76. if(!ok)
  77. {
  78. llwarns << "Application init failed." << llendl;
  79. return -1;
  80. }
  81. // Run the application main loop
  82. if(!LLApp::isQuitting())
  83. {
  84. viewer_app_ptr->mainLoop();
  85. }
  86. if (!LLApp::isError())
  87. {
  88. //
  89. // We don't want to do cleanup here if the error handler got called -
  90. // the assumption is that the error handler is responsible for doing
  91. // app cleanup if there was a problem.
  92. //
  93. viewer_app_ptr->cleanup();
  94. }
  95. delete viewer_app_ptr;
  96. viewer_app_ptr = NULL;
  97. return 0;
  98. }
  99. LLAppViewerLinux::LLAppViewerLinux()
  100. {
  101. }
  102. LLAppViewerLinux::~LLAppViewerLinux()
  103. {
  104. }
  105. bool LLAppViewerLinux::init()
  106. {
  107. // g_thread_init() must be called before *any* use of glib, *and*
  108. // before any mutexes are held, *and* some of our third-party
  109. // libraries likes to use glib functions; in short, do this here
  110. // really early in app startup!
  111. if (!g_thread_supported ()) g_thread_init (NULL);
  112. return LLAppViewer::init();
  113. }
  114. bool LLAppViewerLinux::restoreErrorTrap()
  115. {
  116. // *NOTE:Mani there is a case for implementing this on the mac.
  117. // Linux doesn't need it to my knowledge.
  118. return true;
  119. }
  120. /////////////////////////////////////////
  121. #if LL_DBUS_ENABLED
  122. typedef struct
  123. {
  124. GObjectClass parent_class;
  125. } ViewerAppAPIClass;
  126. static void viewerappapi_init(ViewerAppAPI *server);
  127. static void viewerappapi_class_init(ViewerAppAPIClass *klass);
  128. ///
  129. // regrettable hacks to give us better runtime compatibility with older systems in general
  130. static GType llg_type_register_static_simple_ONCE(GType parent_type,
  131. const gchar *type_name,
  132. guint class_size,
  133. GClassInitFunc class_init,
  134. guint instance_size,
  135. GInstanceInitFunc instance_init,
  136. GTypeFlags flags)
  137. {
  138. static GTypeInfo type_info;
  139. memset(&type_info, 0, sizeof(type_info));
  140. type_info.class_size = class_size;
  141. type_info.class_init = class_init;
  142. type_info.instance_size = instance_size;
  143. type_info.instance_init = instance_init;
  144. return g_type_register_static(parent_type, type_name, &type_info, flags);
  145. }
  146. #define llg_intern_static_string(S) (S)
  147. #define g_intern_static_string(S) llg_intern_static_string(S)
  148. #define g_type_register_static_simple(parent_type, type_name, class_size, class_init, instance_size, instance_init, flags) llg_type_register_static_simple_ONCE(parent_type, type_name, class_size, class_init, instance_size, instance_init, flags)
  149. G_DEFINE_TYPE(ViewerAppAPI, viewerappapi, G_TYPE_OBJECT);
  150. void viewerappapi_class_init(ViewerAppAPIClass *klass)
  151. {
  152. }
  153. static bool dbus_server_init = false;
  154. void viewerappapi_init(ViewerAppAPI *server)
  155. {
  156. // Connect to the default DBUS, register our service/API.
  157. if (!dbus_server_init)
  158. {
  159. GError *error = NULL;
  160. server->connection = lldbus_g_bus_get(DBUS_BUS_SESSION, &error);
  161. if (server->connection)
  162. {
  163. lldbus_g_object_type_install_info(viewerappapi_get_type(), &dbus_glib_viewerapp_object_info);
  164. lldbus_g_connection_register_g_object(server->connection, VIEWERAPI_PATH, G_OBJECT(server));
  165. DBusGProxy *serverproxy = lldbus_g_proxy_new_for_name(server->connection, DBUS_SERVICE_DBUS, DBUS_PATH_DBUS, DBUS_INTERFACE_DBUS);
  166. guint request_name_ret_unused;
  167. // akin to org_freedesktop_DBus_request_name
  168. if (lldbus_g_proxy_call(serverproxy, "RequestName", &error, G_TYPE_STRING, VIEWERAPI_SERVICE, G_TYPE_UINT, 0, G_TYPE_INVALID, G_TYPE_UINT, &request_name_ret_unused, G_TYPE_INVALID))
  169. {
  170. // total success.
  171. dbus_server_init = true;
  172. }
  173. else
  174. {
  175. llwarns << "Unable to register service name: " << error->message << llendl;
  176. }
  177. g_object_unref(serverproxy);
  178. }
  179. else
  180. {
  181. g_warning("Unable to connect to dbus: %s", error->message);
  182. }
  183. if (error)
  184. g_error_free(error);
  185. }
  186. }
  187. gboolean viewer_app_api_GoSLURL(ViewerAppAPI *obj, gchar *slurl, gboolean **success_rtn, GError **error)
  188. {
  189. bool success = false;
  190. llinfos << "Was asked to go to slurl: " << slurl << llendl;
  191. std::string url = slurl;
  192. LLMediaCtrl* web = NULL;
  193. const bool trusted_browser = false;
  194. if (LLURLDispatcher::dispatch(url, "", web, trusted_browser))
  195. {
  196. // bring window to foreground, as it has just been "launched" from a URL
  197. // todo: hmm, how to get there from here?
  198. //xxx->mWindow->bringToFront();
  199. success = true;
  200. }
  201. *success_rtn = g_new (gboolean, 1);
  202. (*success_rtn)[0] = (gboolean)success;
  203. return TRUE; // the invokation succeeded, even if the actual dispatch didn't.
  204. }
  205. ///
  206. //virtual
  207. bool LLAppViewerLinux::initSLURLHandler()
  208. {
  209. if (!grab_dbus_syms(DBUSGLIB_DYLIB_DEFAULT_NAME))
  210. {
  211. return false; // failed
  212. }
  213. g_type_init();
  214. //ViewerAppAPI *api_server = (ViewerAppAPI*)
  215. g_object_new(viewerappapi_get_type(), NULL);
  216. return true;
  217. }
  218. //virtual
  219. bool LLAppViewerLinux::sendURLToOtherInstance(const std::string& url)
  220. {
  221. if (!grab_dbus_syms(DBUSGLIB_DYLIB_DEFAULT_NAME))
  222. {
  223. return false; // failed
  224. }
  225. bool success = false;
  226. DBusGConnection *bus;
  227. GError *error = NULL;
  228. g_type_init();
  229. bus = lldbus_g_bus_get (DBUS_BUS_SESSION, &error);
  230. if (bus)
  231. {
  232. gboolean rtn = FALSE;
  233. DBusGProxy *remote_object =
  234. lldbus_g_proxy_new_for_name(bus, VIEWERAPI_SERVICE, VIEWERAPI_PATH, VIEWERAPI_INTERFACE);
  235. if (lldbus_g_proxy_call(remote_object, "GoSLURL", &error,
  236. G_TYPE_STRING, url.c_str(), G_TYPE_INVALID,
  237. G_TYPE_BOOLEAN, &rtn, G_TYPE_INVALID))
  238. {
  239. success = rtn;
  240. }
  241. else
  242. {
  243. llinfos << "Call-out to other instance failed (perhaps not running): " << error->message << llendl;
  244. }
  245. g_object_unref(G_OBJECT(remote_object));
  246. }
  247. else
  248. {
  249. llwarns << "Couldn't connect to session bus: " << error->message << llendl;
  250. }
  251. if (error)
  252. g_error_free(error);
  253. return success;
  254. }
  255. #else // LL_DBUS_ENABLED
  256. bool LLAppViewerLinux::initSLURLHandler()
  257. {
  258. return false; // not implemented without dbus
  259. }
  260. bool LLAppViewerLinux::sendURLToOtherInstance(const std::string& url)
  261. {
  262. return false; // not implemented without dbus
  263. }
  264. #endif // LL_DBUS_ENABLED
  265. void LLAppViewerLinux::handleCrashReporting(bool reportFreeze)
  266. {
  267. std::string cmd =gDirUtilp->getExecutableDir();
  268. cmd += gDirUtilp->getDirDelimiter();
  269. #if LL_LINUX
  270. cmd += "linux-crash-logger.bin";
  271. #elif LL_SOLARIS
  272. cmd += "solaris-crash-logger";
  273. #else
  274. # error Unknown platform
  275. #endif
  276. if(reportFreeze)
  277. {
  278. char* const cmdargv[] =
  279. {(char*)cmd.c_str(),
  280. (char*)"-previous",
  281. NULL};
  282. fflush(NULL); // flush all buffers before the child inherits them
  283. pid_t pid = fork();
  284. if (pid == 0)
  285. { // child
  286. execv(cmd.c_str(), cmdargv); /* Flawfinder: Ignore */
  287. llwarns << "execv failure when trying to start " << cmd << llendl;
  288. _exit(1); // avoid atexit()
  289. } else {
  290. if (pid > 0)
  291. {
  292. // wait for child proc to die
  293. int childExitStatus;
  294. waitpid(pid, &childExitStatus, 0);
  295. } else {
  296. llwarns << "fork failure." << llendl;
  297. }
  298. }
  299. }
  300. else
  301. {
  302. // launch the actual crash logger
  303. const char * cmdargv[] =
  304. {cmd.c_str(),
  305. "-user",
  306. (char*)LLGridManager::getInstance()->getGridLabel().c_str(),
  307. "-name",
  308. LLAppViewer::instance()->getSecondLifeTitle().c_str(),
  309. NULL};
  310. fflush(NULL);
  311. pid_t pid = fork();
  312. if (pid == 0)
  313. { // child
  314. execv(cmd.c_str(), (char* const*) cmdargv); /* Flawfinder: ignore */
  315. llwarns << "execv failure when trying to start " << cmd << llendl;
  316. _exit(1); // avoid atexit()
  317. }
  318. else
  319. {
  320. if (pid > 0)
  321. {
  322. // DO NOT wait for child proc to die; we want
  323. // the logger to outlive us while we quit to
  324. // free up the screen/keyboard/etc.
  325. ////int childExitStatus;
  326. ////waitpid(pid, &childExitStatus, 0);
  327. }
  328. else
  329. {
  330. llwarns << "fork failure." << llendl;
  331. }
  332. }
  333. // Sometimes signals don't seem to quit the viewer. Also, we may
  334. // have been called explicitly instead of from a signal handler.
  335. // Make sure we exit so as to not totally confuse the user.
  336. _exit(1); // avoid atexit(), else we may re-crash in dtors.
  337. }
  338. }
  339. bool LLAppViewerLinux::beingDebugged()
  340. {
  341. static enum {unknown, no, yes} debugged = unknown;
  342. #if LL_SOLARIS
  343. return debugged == no; // BUG: fix this for Solaris
  344. #else
  345. if (debugged == unknown)
  346. {
  347. pid_t ppid = getppid();
  348. char *name;
  349. int ret;
  350. ret = asprintf(&name, "/proc/%d/exe", ppid);
  351. if (ret != -1)
  352. {
  353. char buf[1024];
  354. ssize_t n;
  355. n = readlink(name, buf, sizeof(buf) - 1);
  356. if (n != -1)
  357. {
  358. char *base = strrchr(buf, '/');
  359. buf[n + 1] = '\0';
  360. if (base == NULL)
  361. {
  362. base = buf;
  363. } else {
  364. base += 1;
  365. }
  366. if (strcmp(base, "gdb") == 0)
  367. {
  368. debugged = yes;
  369. }
  370. }
  371. free(name);
  372. }
  373. }
  374. return debugged == yes;
  375. #endif
  376. }
  377. bool LLAppViewerLinux::initLogging()
  378. {
  379. // Remove the last stack trace, if any
  380. // This file is no longer created, since the move to Google Breakpad
  381. // The code is left here to clean out any old state in the log dir
  382. std::string old_stack_file =
  383. gDirUtilp->getExpandedFilename(LL_PATH_LOGS,"stack_trace.log");
  384. LLFile::remove(old_stack_file);
  385. return LLAppViewer::initLogging();
  386. }
  387. bool LLAppViewerLinux::initParseCommandLine(LLCommandLineParser& clp)
  388. {
  389. if (!clp.parseCommandLine(gArgC, gArgV))
  390. {
  391. return false;
  392. }
  393. // Find the system language.
  394. FL_Locale *locale = NULL;
  395. FL_Success success = FL_FindLocale(&locale, FL_MESSAGES);
  396. if (success != 0)
  397. {
  398. if (success >= 2 && locale->lang) // confident!
  399. {
  400. LL_INFOS("AppInit") << "Language " << ll_safe_string(locale->lang) << LL_ENDL;
  401. LL_INFOS("AppInit") << "Location " << ll_safe_string(locale->country) << LL_ENDL;
  402. LL_INFOS("AppInit") << "Variant " << ll_safe_string(locale->variant) << LL_ENDL;
  403. LLControlVariable* c = gSavedSettings.getControl("SystemLanguage");
  404. if(c)
  405. {
  406. c->setValue(std::string(locale->lang), false);
  407. }
  408. }
  409. }
  410. FL_FreeLocale(&locale);
  411. return true;
  412. }
  413. std::string LLAppViewerLinux::generateSerialNumber()
  414. {
  415. char serial_md5[MD5HEX_STR_SIZE];
  416. serial_md5[0] = 0;
  417. std::string best;
  418. std::string uuiddir("/dev/disk/by-uuid/");
  419. // trawl /dev/disk/by-uuid looking for a good-looking UUID to grab
  420. std::string this_name;
  421. LLDirIterator iter(uuiddir, "*");
  422. while (iter.next(this_name))
  423. {
  424. if (this_name.length() > best.length() ||
  425. (this_name.length() == best.length() &&
  426. this_name > best))
  427. {
  428. // longest (and secondarily alphabetically last) so far
  429. best = this_name;
  430. }
  431. }
  432. // we don't return the actual serial number, just a hash of it.
  433. LLMD5 md5( reinterpret_cast<const unsigned char*>(best.c_str()) );
  434. md5.hex_digest(serial_md5);
  435. return serial_md5;
  436. }