mobile/android/base/mozglue/GeckoLoader.java.in

Thu, 22 Jan 2015 13:21:57 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Thu, 22 Jan 2015 13:21:57 +0100
branch
TOR_BUG_9701
changeset 15
b8a032363ba2
permissions
-rw-r--r--

Incorporate requested changes from Mozilla in review:
https://bugzilla.mozilla.org/show_bug.cgi?id=1123480#c6

michael@0 1 #filter substitution
michael@0 2 /* -*- Mode: Java; c-basic-offset: 4; tab-width: 20; indent-tabs-mode: nil; -*-
michael@0 3 * This Source Code Form is subject to the terms of the Mozilla Public
michael@0 4 * License, v. 2.0. If a copy of the MPL was not distributed with this
michael@0 5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
michael@0 6
michael@0 7 package org.mozilla.gecko.mozglue;
michael@0 8
michael@0 9 import android.content.Context;
michael@0 10 import android.content.Intent;
michael@0 11 import android.os.Build;
michael@0 12 import android.os.Environment;
michael@0 13 import android.util.Log;
michael@0 14
michael@0 15 import java.io.File;
michael@0 16 import java.text.DecimalFormat;
michael@0 17 import java.text.DecimalFormatSymbols;
michael@0 18 import java.text.NumberFormat;
michael@0 19 import java.util.Locale;
michael@0 20
michael@0 21 public final class GeckoLoader {
michael@0 22 private static final String LOGTAG = "GeckoLoader";
michael@0 23
michael@0 24 // This matches AppConstants, but we're built earlier.
michael@0 25 private static final String ANDROID_PACKAGE_NAME = "@ANDROID_PACKAGE_NAME@";
michael@0 26
michael@0 27 private static volatile Intent sIntent;
michael@0 28 private static File sCacheFile;
michael@0 29 private static File sGREDir;
michael@0 30
michael@0 31 private static final Object sLibLoadingLock = new Object();
michael@0 32 // Must hold sLibLoadingLock while accessing the following boolean variables.
michael@0 33 private static boolean sSQLiteLibsLoaded;
michael@0 34 private static boolean sNSSLibsLoaded;
michael@0 35 private static boolean sMozGlueLoaded;
michael@0 36 private static boolean sLibsSetup;
michael@0 37
michael@0 38 private GeckoLoader() {
michael@0 39 // prevent instantiation
michael@0 40 }
michael@0 41
michael@0 42 public static File getCacheDir(Context context) {
michael@0 43 if (sCacheFile == null) {
michael@0 44 sCacheFile = context.getCacheDir();
michael@0 45 }
michael@0 46 return sCacheFile;
michael@0 47 }
michael@0 48
michael@0 49 public static File getGREDir(Context context) {
michael@0 50 if (sGREDir == null) {
michael@0 51 sGREDir = new File(context.getApplicationInfo().dataDir);
michael@0 52 }
michael@0 53 return sGREDir;
michael@0 54 }
michael@0 55
michael@0 56 private static void setupPluginEnvironment(Context context, String[] pluginDirs) {
michael@0 57 // setup plugin path directories
michael@0 58 try {
michael@0 59 // Check to see if plugins were blocked.
michael@0 60 if (pluginDirs == null) {
michael@0 61 putenv("MOZ_PLUGINS_BLOCKED=1");
michael@0 62 putenv("MOZ_PLUGIN_PATH=");
michael@0 63 return;
michael@0 64 }
michael@0 65
michael@0 66 StringBuilder pluginSearchPath = new StringBuilder();
michael@0 67 for (int i = 0; i < pluginDirs.length; i++) {
michael@0 68 pluginSearchPath.append(pluginDirs[i]);
michael@0 69 pluginSearchPath.append(":");
michael@0 70 }
michael@0 71 putenv("MOZ_PLUGIN_PATH="+pluginSearchPath);
michael@0 72
michael@0 73 File pluginDataDir = context.getDir("plugins", 0);
michael@0 74 putenv("ANDROID_PLUGIN_DATADIR=" + pluginDataDir.getPath());
michael@0 75
michael@0 76 File pluginPrivateDataDir = context.getDir("plugins_private", 0);
michael@0 77 putenv("ANDROID_PLUGIN_DATADIR_PRIVATE=" + pluginPrivateDataDir.getPath());
michael@0 78
michael@0 79 } catch (Exception ex) {
michael@0 80 Log.w(LOGTAG, "Caught exception getting plugin dirs.", ex);
michael@0 81 }
michael@0 82 }
michael@0 83
michael@0 84 private static void setupDownloadEnvironment(Context context) {
michael@0 85 try {
michael@0 86 File downloadDir = null;
michael@0 87 File updatesDir = null;
michael@0 88 if (Build.VERSION.SDK_INT >= 8) {
michael@0 89 downloadDir = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS);
michael@0 90 updatesDir = context.getExternalFilesDir(Environment.DIRECTORY_DOWNLOADS);
michael@0 91 }
michael@0 92 if (downloadDir == null) {
michael@0 93 downloadDir = new File(Environment.getExternalStorageDirectory().getPath(), "download");
michael@0 94 }
michael@0 95 if (updatesDir == null) {
michael@0 96 updatesDir = downloadDir;
michael@0 97 }
michael@0 98 putenv("DOWNLOADS_DIRECTORY=" + downloadDir.getPath());
michael@0 99 putenv("UPDATES_DIRECTORY=" + updatesDir.getPath());
michael@0 100 }
michael@0 101 catch (Exception e) {
michael@0 102 Log.w(LOGTAG, "No download directory found.", e);
michael@0 103 }
michael@0 104 }
michael@0 105
michael@0 106 private static void delTree(File file) {
michael@0 107 if (file.isDirectory()) {
michael@0 108 File children[] = file.listFiles();
michael@0 109 for (File child : children) {
michael@0 110 delTree(child);
michael@0 111 }
michael@0 112 }
michael@0 113 file.delete();
michael@0 114 }
michael@0 115
michael@0 116 private static File getTmpDir(Context context) {
michael@0 117 File tmpDir = context.getDir("tmpdir", Context.MODE_PRIVATE);
michael@0 118 // check if the old tmp dir is there
michael@0 119 File oldDir = new File(tmpDir.getParentFile(), "app_tmp");
michael@0 120 if (oldDir.exists()) {
michael@0 121 delTree(oldDir);
michael@0 122 }
michael@0 123 return tmpDir;
michael@0 124 }
michael@0 125
michael@0 126 public static void setLastIntent(Intent intent) {
michael@0 127 sIntent = intent;
michael@0 128 }
michael@0 129
michael@0 130 public static void setupGeckoEnvironment(Context context, String[] pluginDirs, String profilePath) {
michael@0 131 // if we have an intent (we're being launched by an activity)
michael@0 132 // read in any environmental variables from it here
michael@0 133 final Intent intent = sIntent;
michael@0 134 if (intent != null) {
michael@0 135 String env = intent.getStringExtra("env0");
michael@0 136 Log.d(LOGTAG, "Gecko environment env0: " + env);
michael@0 137 for (int c = 1; env != null; c++) {
michael@0 138 putenv(env);
michael@0 139 env = intent.getStringExtra("env" + c);
michael@0 140 Log.d(LOGTAG, "env" + c + ": " + env);
michael@0 141 }
michael@0 142 }
michael@0 143
michael@0 144 setupPluginEnvironment(context, pluginDirs);
michael@0 145 setupDownloadEnvironment(context);
michael@0 146
michael@0 147 // profile home path
michael@0 148 putenv("HOME=" + profilePath);
michael@0 149
michael@0 150 // setup the tmp path
michael@0 151 File f = getTmpDir(context);
michael@0 152 if (!f.exists()) {
michael@0 153 f.mkdirs();
michael@0 154 }
michael@0 155 putenv("TMPDIR=" + f.getPath());
michael@0 156
michael@0 157 // setup the downloads path
michael@0 158 f = Environment.getDownloadCacheDirectory();
michael@0 159 putenv("EXTERNAL_STORAGE=" + f.getPath());
michael@0 160
michael@0 161 // setup the app-specific cache path
michael@0 162 f = context.getCacheDir();
michael@0 163 putenv("CACHE_DIRECTORY=" + f.getPath());
michael@0 164
michael@0 165 /* We really want to use this code, but it requires bumping up the SDK to 17 so for now
michael@0 166 we will use reflection. See https://bugzilla.mozilla.org/show_bug.cgi?id=811763#c11
michael@0 167
michael@0 168 if (Build.VERSION.SDK_INT >= 17) {
michael@0 169 android.os.UserManager um = (android.os.UserManager)context.getSystemService(Context.USER_SERVICE);
michael@0 170 if (um != null) {
michael@0 171 putenv("MOZ_ANDROID_USER_SERIAL_NUMBER=" + um.getSerialNumberForUser(android.os.Process.myUserHandle()));
michael@0 172 } else {
michael@0 173 Log.d(LOGTAG, "Unable to obtain user manager service on a device with SDK version " + Build.VERSION.SDK_INT);
michael@0 174 }
michael@0 175 }
michael@0 176 */
michael@0 177 try {
michael@0 178 Object userManager = context.getSystemService("user");
michael@0 179 if (userManager != null) {
michael@0 180 // if userManager is non-null that means we're running on 4.2+ and so the rest of this
michael@0 181 // should just work
michael@0 182 Object userHandle = android.os.Process.class.getMethod("myUserHandle", (Class[])null).invoke(null);
michael@0 183 Object userSerial = userManager.getClass().getMethod("getSerialNumberForUser", userHandle.getClass()).invoke(userManager, userHandle);
michael@0 184 putenv("MOZ_ANDROID_USER_SERIAL_NUMBER=" + userSerial.toString());
michael@0 185 }
michael@0 186 } catch (Exception e) {
michael@0 187 // Guard against any unexpected failures
michael@0 188 Log.d(LOGTAG, "Unable to set the user serial number", e);
michael@0 189 }
michael@0 190
michael@0 191 setupLocaleEnvironment();
michael@0 192
michael@0 193 // We don't need this any more.
michael@0 194 sIntent = null;
michael@0 195 }
michael@0 196
michael@0 197 private static void loadLibsSetup(Context context) {
michael@0 198 synchronized (sLibLoadingLock) {
michael@0 199 if (sLibsSetup) {
michael@0 200 return;
michael@0 201 }
michael@0 202 sLibsSetup = true;
michael@0 203 }
michael@0 204
michael@0 205 // The package data lib directory isn't placed in ld.so's
michael@0 206 // search path, so we have to manually load libraries that
michael@0 207 // libxul will depend on. Not ideal.
michael@0 208
michael@0 209 File cacheFile = getCacheDir(context);
michael@0 210 putenv("GRE_HOME=" + getGREDir(context).getPath());
michael@0 211
michael@0 212 // setup the libs cache
michael@0 213 String linkerCache = System.getenv("MOZ_LINKER_CACHE");
michael@0 214 if (linkerCache == null) {
michael@0 215 linkerCache = cacheFile.getPath();
michael@0 216 putenv("MOZ_LINKER_CACHE=" + linkerCache);
michael@0 217 }
michael@0 218
michael@0 219 // Disable on-demand decompression of the linker on devices where it
michael@0 220 // is known to cause crashes.
michael@0 221 if ("HTC".equals(android.os.Build.MANUFACTURER) &&
michael@0 222 "HTC Vision".equals(android.os.Build.MODEL)) {
michael@0 223 putenv("MOZ_LINKER_ONDEMAND=0");
michael@0 224 }
michael@0 225
michael@0 226 #ifdef MOZ_LINKER_EXTRACT
michael@0 227 putenv("MOZ_LINKER_EXTRACT=1");
michael@0 228 // Ensure that the cache dir is world-writable
michael@0 229 File cacheDir = new File(linkerCache);
michael@0 230 if (cacheDir.isDirectory()) {
michael@0 231 cacheDir.setWritable(true, false);
michael@0 232 cacheDir.setExecutable(true, false);
michael@0 233 cacheDir.setReadable(true, false);
michael@0 234 }
michael@0 235 #endif
michael@0 236 }
michael@0 237
michael@0 238 @RobocopTarget
michael@0 239 public static void loadSQLiteLibs(Context context, String apkName) {
michael@0 240 synchronized (sLibLoadingLock) {
michael@0 241 if (sSQLiteLibsLoaded) {
michael@0 242 return;
michael@0 243 }
michael@0 244 sSQLiteLibsLoaded = true;
michael@0 245 }
michael@0 246
michael@0 247 loadMozGlue();
michael@0 248 // the extract libs parameter is being removed in bug 732069
michael@0 249 loadLibsSetup(context);
michael@0 250 loadSQLiteLibsNative(apkName, false);
michael@0 251 }
michael@0 252
michael@0 253 public static void loadNSSLibs(Context context, String apkName) {
michael@0 254 synchronized (sLibLoadingLock) {
michael@0 255 if (sNSSLibsLoaded) {
michael@0 256 return;
michael@0 257 }
michael@0 258 sNSSLibsLoaded = true;
michael@0 259 }
michael@0 260
michael@0 261 loadMozGlue();
michael@0 262 loadLibsSetup(context);
michael@0 263 loadNSSLibsNative(apkName, false);
michael@0 264 }
michael@0 265
michael@0 266 public static void doLoadLibrary(final String lib) {
michael@0 267 try {
michael@0 268 System.loadLibrary(lib);
michael@0 269 } catch (UnsatisfiedLinkError e) {
michael@0 270 Log.wtf(LOGTAG, "Couldn't load " + lib + ". Trying /data/app-lib path.");
michael@0 271 try {
michael@0 272 System.load("/data/app-lib/" + ANDROID_PACKAGE_NAME + "/lib" + lib + ".so");
michael@0 273 } catch (Throwable ee) {
michael@0 274 try {
michael@0 275 Log.wtf(LOGTAG, "Couldn't load " + lib + ": " + ee + ". Trying /data/data path.");
michael@0 276 System.load("/data/data/" + ANDROID_PACKAGE_NAME + "/lib/lib" + lib + ".so");
michael@0 277 } catch (Throwable eee) {
michael@0 278 Log.wtf(LOGTAG, "Failed every attempt to load " + lib + ". Giving up.");
michael@0 279 throw new RuntimeException("Unable to load " + lib, eee);
michael@0 280 }
michael@0 281 }
michael@0 282 }
michael@0 283 }
michael@0 284
michael@0 285 public static void loadMozGlue() {
michael@0 286 synchronized (sLibLoadingLock) {
michael@0 287 if (sMozGlueLoaded) {
michael@0 288 return;
michael@0 289 }
michael@0 290 sMozGlueLoaded = true;
michael@0 291 }
michael@0 292
michael@0 293 doLoadLibrary("mozglue");
michael@0 294 }
michael@0 295
michael@0 296 public static void loadGeckoLibs(Context context, String apkName) {
michael@0 297 loadLibsSetup(context);
michael@0 298 loadGeckoLibsNative(apkName);
michael@0 299 }
michael@0 300
michael@0 301 private static void setupLocaleEnvironment() {
michael@0 302 putenv("LANG=" + Locale.getDefault().toString());
michael@0 303 NumberFormat nf = NumberFormat.getInstance();
michael@0 304 if (nf instanceof DecimalFormat) {
michael@0 305 DecimalFormat df = (DecimalFormat)nf;
michael@0 306 DecimalFormatSymbols dfs = df.getDecimalFormatSymbols();
michael@0 307
michael@0 308 putenv("LOCALE_DECIMAL_POINT=" + dfs.getDecimalSeparator());
michael@0 309 putenv("LOCALE_THOUSANDS_SEP=" + dfs.getGroupingSeparator());
michael@0 310 putenv("LOCALE_GROUPING=" + (char)df.getGroupingSize());
michael@0 311 }
michael@0 312 }
michael@0 313
michael@0 314 // These methods are implemented in mozglue/android/nsGeckoUtils.cpp
michael@0 315 private static native void putenv(String map);
michael@0 316
michael@0 317 // These methods are implemented in mozglue/android/APKOpen.cpp
michael@0 318 public static native void nativeRun(String args);
michael@0 319 private static native void loadGeckoLibsNative(String apkName);
michael@0 320 private static native void loadSQLiteLibsNative(String apkName, boolean shouldExtract);
michael@0 321 private static native void loadNSSLibsNative(String apkName, boolean shouldExtract);
michael@0 322 }

mercurial