accessible/src/atk/Platform.cpp

Tue, 06 Jan 2015 21:39:09 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Tue, 06 Jan 2015 21:39:09 +0100
branch
TOR_BUG_9701
changeset 8
97036ab72558
permissions
-rw-r--r--

Conditionally force memory storage according to privacy.thirdparty.isolate;
This solves Tor bug #9701, complying with disk avoidance documented in
https://www.torproject.org/projects/torbrowser/design/#disk-avoidance.

     1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
     2 /* vim: set ts=2 et sw=2 tw=80: */
     3 /* This Source Code Form is subject to the terms of the Mozilla Public
     4  * License, v. 2.0. If a copy of the MPL was not distributed with this
     5  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
     7 #include "Platform.h"
     9 #include "nsIAccessibleEvent.h"
    10 #include "nsIGConfService.h"
    11 #include "nsIServiceManager.h"
    12 #include "nsMai.h"
    13 #include "AtkSocketAccessible.h"
    14 #include "prenv.h"
    15 #include "prlink.h"
    17 #ifdef MOZ_ENABLE_DBUS
    18 #include <dbus/dbus.h>
    19 #endif
    20 #include <gtk/gtk.h>
    22 using namespace mozilla;
    23 using namespace mozilla::a11y;
    25 int atkMajorVersion = 1, atkMinorVersion = 12;
    27 extern "C" {
    28 typedef GType (* AtkGetTypeType) (void);
    29 typedef void (*GnomeAccessibilityInit) (void);
    30 typedef void (*GnomeAccessibilityShutdown) (void);
    31 }
    33 static PRLibrary* sATKLib = nullptr;
    34 static const char sATKLibName[] = "libatk-1.0.so.0";
    35 static const char sATKHyperlinkImplGetTypeSymbol[] =
    36   "atk_hyperlink_impl_get_type";
    38 gboolean toplevel_event_watcher(GSignalInvocationHint*, guint, const GValue*,
    39                                 gpointer);
    40 static bool sToplevel_event_hook_added = false;
    41 static gulong sToplevel_show_hook = 0;
    42 static gulong sToplevel_hide_hook = 0;
    44 GType g_atk_hyperlink_impl_type = G_TYPE_INVALID;
    46 struct GnomeAccessibilityModule
    47 {
    48     const char *libName;
    49     PRLibrary *lib;
    50     const char *initName;
    51     GnomeAccessibilityInit init;
    52     const char *shutdownName;
    53     GnomeAccessibilityShutdown shutdown;
    54 };
    56 static GnomeAccessibilityModule sAtkBridge = {
    57 #ifdef AIX
    58     "libatk-bridge.a(libatk-bridge.so.0)", nullptr,
    59 #else
    60     "libatk-bridge.so", nullptr,
    61 #endif
    62     "gnome_accessibility_module_init", nullptr,
    63     "gnome_accessibility_module_shutdown", nullptr
    64 };
    66 static GnomeAccessibilityModule sGail = {
    67     "libgail.so", nullptr,
    68     "gnome_accessibility_module_init", nullptr,
    69     "gnome_accessibility_module_shutdown", nullptr
    70 };
    72 static nsresult
    73 LoadGtkModule(GnomeAccessibilityModule& aModule)
    74 {
    75     NS_ENSURE_ARG(aModule.libName);
    77     if (!(aModule.lib = PR_LoadLibrary(aModule.libName))) {
    78         //try to load the module with "gtk-2.0/modules" appended
    79         char *curLibPath = PR_GetLibraryPath();
    80         nsAutoCString libPath(curLibPath);
    81 #if defined(LINUX) && defined(__x86_64__)
    82         libPath.Append(":/usr/lib64:/usr/lib");
    83 #else
    84         libPath.Append(":/usr/lib");
    85 #endif
    86         PR_FreeLibraryName(curLibPath);
    88         int16_t loc1 = 0, loc2 = 0;
    89         int16_t subLen = 0;
    90         while (loc2 >= 0) {
    91             loc2 = libPath.FindChar(':', loc1);
    92             if (loc2 < 0)
    93                 subLen = libPath.Length() - loc1;
    94             else
    95                 subLen = loc2 - loc1;
    96             nsAutoCString sub(Substring(libPath, loc1, subLen));
    97             sub.Append("/gtk-2.0/modules/");
    98             sub.Append(aModule.libName);
    99             aModule.lib = PR_LoadLibrary(sub.get());
   100             if (aModule.lib)
   101                 break;
   103             loc1 = loc2+1;
   104         }
   105         if (!aModule.lib)
   106             return NS_ERROR_FAILURE;
   107     }
   109     //we have loaded the library, try to get the function ptrs
   110     if (!(aModule.init = PR_FindFunctionSymbol(aModule.lib,
   111                                                aModule.initName)) ||
   112         !(aModule.shutdown = PR_FindFunctionSymbol(aModule.lib,
   113                                                    aModule.shutdownName))) {
   115         //fail, :(
   116         PR_UnloadLibrary(aModule.lib);
   117         aModule.lib = nullptr;
   118         return NS_ERROR_FAILURE;
   119     }
   120     return NS_OK;
   121 }
   123 void
   124 a11y::PlatformInit()
   125 {
   126   if (!ShouldA11yBeEnabled())
   127     return;
   129   sATKLib = PR_LoadLibrary(sATKLibName);
   130   if (!sATKLib)
   131     return;
   133   AtkGetTypeType pfn_atk_hyperlink_impl_get_type =
   134     (AtkGetTypeType) PR_FindFunctionSymbol(sATKLib, sATKHyperlinkImplGetTypeSymbol);
   135   if (pfn_atk_hyperlink_impl_get_type)
   136     g_atk_hyperlink_impl_type = pfn_atk_hyperlink_impl_get_type();
   138   AtkGetTypeType pfn_atk_socket_get_type = (AtkGetTypeType)
   139     PR_FindFunctionSymbol(sATKLib, AtkSocketAccessible::sATKSocketGetTypeSymbol);
   140   if (pfn_atk_socket_get_type) {
   141     AtkSocketAccessible::g_atk_socket_type = pfn_atk_socket_get_type();
   142     AtkSocketAccessible::g_atk_socket_embed = (AtkSocketEmbedType)
   143       PR_FindFunctionSymbol(sATKLib, AtkSocketAccessible ::sATKSocketEmbedSymbol);
   144     AtkSocketAccessible::gCanEmbed =
   145       AtkSocketAccessible::g_atk_socket_type != G_TYPE_INVALID &&
   146       AtkSocketAccessible::g_atk_socket_embed;
   147   }
   149   const char* (*atkGetVersion)() =
   150     (const char* (*)()) PR_FindFunctionSymbol(sATKLib, "atk_get_version");
   151   if (atkGetVersion) {
   152     const char* version = atkGetVersion();
   153     if (version) {
   154       char* endPtr = nullptr;
   155       atkMajorVersion = strtol(version, &endPtr, 10);
   156       if (*endPtr == '.')
   157         atkMinorVersion = strtol(endPtr + 1, &endPtr, 10);
   158     }
   159   }
   161   // Load and initialize gail library.
   162   nsresult rv = LoadGtkModule(sGail);
   163   if (NS_SUCCEEDED(rv))
   164     (*sGail.init)();
   166   // Initialize the MAI Utility class, it will overwrite gail_util.
   167   g_type_class_unref(g_type_class_ref(mai_util_get_type()));
   169   // Init atk-bridge now
   170   PR_SetEnv("NO_AT_BRIDGE=0");
   171   rv = LoadGtkModule(sAtkBridge);
   172   if (NS_SUCCEEDED(rv)) {
   173     (*sAtkBridge.init)();
   174   }
   176   if (!sToplevel_event_hook_added) {
   177     sToplevel_event_hook_added = true;
   178     sToplevel_show_hook =
   179       g_signal_add_emission_hook(g_signal_lookup("show", GTK_TYPE_WINDOW),
   180                                  0, toplevel_event_watcher,
   181                                  reinterpret_cast<gpointer>(nsIAccessibleEvent::EVENT_SHOW),
   182                                  nullptr);
   183     sToplevel_hide_hook =
   184       g_signal_add_emission_hook(g_signal_lookup("hide", GTK_TYPE_WINDOW), 0,
   185                                  toplevel_event_watcher,
   186                                  reinterpret_cast<gpointer>(nsIAccessibleEvent::EVENT_HIDE),
   187                                  nullptr);
   188   }
   189 }
   191 void
   192 a11y::PlatformShutdown()
   193 {
   194     if (sToplevel_event_hook_added) {
   195       sToplevel_event_hook_added = false;
   196       g_signal_remove_emission_hook(g_signal_lookup("show", GTK_TYPE_WINDOW),
   197                                     sToplevel_show_hook);
   198       g_signal_remove_emission_hook(g_signal_lookup("hide", GTK_TYPE_WINDOW),
   199                                     sToplevel_hide_hook);
   200     }
   202     if (sAtkBridge.lib) {
   203         // Do not shutdown/unload atk-bridge,
   204         // an exit function registered will take care of it
   205         // if (sAtkBridge.shutdown)
   206         //     (*sAtkBridge.shutdown)();
   207         // PR_UnloadLibrary(sAtkBridge.lib);
   208         sAtkBridge.lib = nullptr;
   209         sAtkBridge.init = nullptr;
   210         sAtkBridge.shutdown = nullptr;
   211     }
   212     if (sGail.lib) {
   213         // Do not shutdown gail because
   214         // 1) Maybe it's not init-ed by us. e.g. GtkEmbed
   215         // 2) We need it to avoid assert in spi_atk_tidy_windows
   216         // if (sGail.shutdown)
   217         //   (*sGail.shutdown)();
   218         // PR_UnloadLibrary(sGail.lib);
   219         sGail.lib = nullptr;
   220         sGail.init = nullptr;
   221         sGail.shutdown = nullptr;
   222     }
   223     // if (sATKLib) {
   224     //     PR_UnloadLibrary(sATKLib);
   225     //     sATKLib = nullptr;
   226     // }
   227 }
   229   static const char sAccEnv [] = "GNOME_ACCESSIBILITY";
   230 #ifdef MOZ_ENABLE_DBUS
   231 static DBusPendingCall *sPendingCall = nullptr;
   232 #endif
   234 void
   235 a11y::PreInit()
   236 {
   237 #ifdef MOZ_ENABLE_DBUS
   238   static bool sChecked = FALSE;
   239   if (sChecked)
   240     return;
   242   sChecked = TRUE;
   244   // dbus is only checked if GNOME_ACCESSIBILITY is unset
   245   // also make sure that a session bus address is available to prevent dbus from
   246   // starting a new one.  Dbus confuses the test harness when it creates a new
   247   // process (see bug 693343)
   248   if (PR_GetEnv(sAccEnv) || !PR_GetEnv("DBUS_SESSION_BUS_ADDRESS"))
   249     return;
   251   DBusConnection* bus = dbus_bus_get(DBUS_BUS_SESSION, nullptr);
   252   if (!bus)
   253     return;
   255   dbus_connection_set_exit_on_disconnect(bus, FALSE);
   257   static const char* iface = "org.a11y.Status";
   258   static const char* member = "IsEnabled";
   259   DBusMessage *message;
   260   message = dbus_message_new_method_call("org.a11y.Bus", "/org/a11y/bus",
   261                                          "org.freedesktop.DBus.Properties",
   262                                          "Get");
   263   if (!message)
   264     goto dbus_done;
   266   dbus_message_append_args(message, DBUS_TYPE_STRING, &iface,
   267                            DBUS_TYPE_STRING, &member, DBUS_TYPE_INVALID);
   268   dbus_connection_send_with_reply(bus, message, &sPendingCall, 1000);
   269   dbus_message_unref(message);
   271 dbus_done:
   272   dbus_connection_unref(bus);
   273 #endif
   274 }
   276 bool
   277 a11y::ShouldA11yBeEnabled()
   278 {
   279   static bool sChecked = false, sShouldEnable = false;
   280   if (sChecked)
   281     return sShouldEnable;
   283   sChecked = true;
   285   EPlatformDisabledState disabledState = PlatformDisabledState();
   286   if (disabledState == ePlatformIsDisabled)
   287     return sShouldEnable = false;
   289   // check if accessibility enabled/disabled by environment variable
   290   const char* envValue = PR_GetEnv(sAccEnv);
   291   if (envValue)
   292     return sShouldEnable = !!atoi(envValue);
   294 #ifdef MOZ_ENABLE_DBUS
   295   PreInit();
   296   bool dbusSuccess = false;
   297   DBusMessage *reply = nullptr;
   298   if (!sPendingCall)
   299     goto dbus_done;
   301   dbus_pending_call_block(sPendingCall);
   302   reply = dbus_pending_call_steal_reply(sPendingCall);
   303   dbus_pending_call_unref(sPendingCall);
   304   sPendingCall = nullptr;
   305   if (!reply ||
   306       dbus_message_get_type(reply) != DBUS_MESSAGE_TYPE_METHOD_RETURN ||
   307       strcmp(dbus_message_get_signature (reply), DBUS_TYPE_VARIANT_AS_STRING))
   308     goto dbus_done;
   310   DBusMessageIter iter, iter_variant, iter_struct;
   311   dbus_bool_t dResult;
   312   dbus_message_iter_init(reply, &iter);
   313   dbus_message_iter_recurse (&iter, &iter_variant);
   314   switch (dbus_message_iter_get_arg_type(&iter_variant)) {
   315     case DBUS_TYPE_STRUCT:
   316       // at-spi2-core 2.2.0-2.2.1 had a bug where it returned a struct
   317       dbus_message_iter_recurse(&iter_variant, &iter_struct);
   318       if (dbus_message_iter_get_arg_type(&iter_struct) == DBUS_TYPE_BOOLEAN) {
   319         dbus_message_iter_get_basic(&iter_struct, &dResult);
   320         sShouldEnable = dResult;
   321         dbusSuccess = true;
   322       }
   324       break;
   325     case DBUS_TYPE_BOOLEAN:
   326       dbus_message_iter_get_basic(&iter_variant, &dResult);
   327       sShouldEnable = dResult;
   328       dbusSuccess = true;
   329       break;
   330     default:
   331       break;
   332   }
   334 dbus_done:
   335   if (reply)
   336     dbus_message_unref(reply);
   338   if (dbusSuccess)
   339     return sShouldEnable;
   340 #endif
   342   //check gconf-2 setting
   343 static const char sGconfAccessibilityKey[] =
   344     "/desktop/gnome/interface/accessibility";
   345   nsresult rv = NS_OK;
   346   nsCOMPtr<nsIGConfService> gconf =
   347     do_GetService(NS_GCONFSERVICE_CONTRACTID, &rv);
   348   if (NS_SUCCEEDED(rv) && gconf)
   349     gconf->GetBool(NS_LITERAL_CSTRING(sGconfAccessibilityKey), &sShouldEnable);
   351   return sShouldEnable;
   352 }

mercurial