Bug 1355870 - Allow a system preference to determine distribution dir. r=nalexander, a=lizzard
authorMichael Kaply <mozilla@kaply.com>
Thu, 13 Apr 2017 20:04:41 -0500
changeset 396036 f14e5d09f00da2751b6ed35a8b566c7f134f4559
parent 396035 4bde1b05f7bf61e39ba8d3679b2ea73c58bea0e4
child 396037 e20007000f8e56cefca0a93788be3ac05f0823fc
push id1468
push userasasaki@mozilla.com
push dateMon, 05 Jun 2017 19:31:07 +0000
treeherdermozilla-release@0641fc6ee9d1 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersnalexander, lizzard
bugs1355870
milestone54.0
Bug 1355870 - Allow a system preference to determine distribution dir. r=nalexander, a=lizzard
mobile/android/base/java/org/mozilla/gecko/distribution/Distribution.java
--- a/mobile/android/base/java/org/mozilla/gecko/distribution/Distribution.java
+++ b/mobile/android/base/java/org/mozilla/gecko/distribution/Distribution.java
@@ -7,16 +7,17 @@ package org.mozilla.gecko.distribution;
 
 import java.io.BufferedInputStream;
 import java.io.File;
 import java.io.FileNotFoundException;
 import java.io.FileOutputStream;
 import java.io.IOException;
 import java.io.InputStream;
 import java.io.OutputStream;
+import java.lang.reflect.Method;
 import java.net.HttpURLConnection;
 import java.net.ProtocolException;
 import java.net.SocketException;
 import java.net.URI;
 import java.net.URISyntaxException;
 import java.net.UnknownHostException;
 import java.util.Collections;
 import java.util.Enumeration;
@@ -77,17 +78,20 @@ public class Distribution {
 
     /**
      * Telemetry constants.
      */
     private static final String HISTOGRAM_REFERRER_INVALID = "FENNEC_DISTRIBUTION_REFERRER_INVALID";
     private static final String HISTOGRAM_DOWNLOAD_TIME_MS = "FENNEC_DISTRIBUTION_DOWNLOAD_TIME_MS";
     private static final String HISTOGRAM_CODE_CATEGORY = "FENNEC_DISTRIBUTION_CODE_CATEGORY";
 
+    // This is the name of the system property used to discover a custom distribution directory.
+    private static final String SYSPROP_DISTRIBUTIONDIR = "ro.org.mozilla.distributiondir";
     /**
+     *
      * Success/failure codes. Don't exceed the maximum listed in Histograms.json.
      */
     private static final int CODE_CATEGORY_STATUS_OUT_OF_RANGE = 0;
     // HTTP status 'codes' run from 1 to 5.
     private static final int CODE_CATEGORY_OFFLINE = 6;
     private static final int CODE_CATEGORY_FETCH_EXCEPTION = 7;
 
     // It's a post-fetch exception if we were able to download, but not
@@ -919,25 +923,67 @@ public class Distribution {
 
         System.arraycopy(dataDirectories, 0, directories, 0, dataDirectories.length);
         System.arraycopy(systemDirectories, 0, directories, dataDirectories.length, systemDirectories.length);
 
         return directories;
     }
 
     /**
+     * This function checks to see if a custom distribution directory has
+     * been set as a system property and returns it if it exists. The path
+     * returned will always have a single trailing slash.
+     *
+     * The system property is readonly, so it can only be set by vendors or
+     * someone with a rooted device.
+     *
+     * The mechanism to obtain the property is necessary because retrieval
+     * methods are not exposed in the SDK.
+     */
+    private static String getDistributionDirectoryFromSystemProperty() {
+        try {
+            @SuppressWarnings("rawtypes")
+            Class clazz = Class.forName("android.os.SystemProperties");
+            @SuppressWarnings("unchecked")
+            Method method = clazz.getDeclaredMethod("get", String.class);
+            String distDirName = (String)method.invoke(null, SYSPROP_DISTRIBUTIONDIR);
+            if (!distDirName.isEmpty()) {
+                Log.d(LOGTAG, "System property " + SYSPROP_DISTRIBUTIONDIR + " found with value " + distDirName);
+                // Add a trailing slash if it isn't there
+                if (distDirName.charAt(distDirName.length() - 1) != '/') {
+                    distDirName += '/';
+                }
+                File distDir = new File(distDirName);
+                if (distDir.exists() && distDir.isDirectory()) {
+                    Log.d(LOGTAG, "Custom distribution directory found at " + distDirName);
+                    return distDirName;
+                }
+            }
+        } catch (Exception e) {
+            Log.e(LOGTAG, "Error getting system property " + SYSPROP_DISTRIBUTIONDIR, e);
+        }
+        Log.d(LOGTAG, "Custom distribution directory not found.");
+        return null;
+    }
+    /**
      * Get a list of system distribution folder candidates.
      *
      * /system/<package>/distribution/<mcc>/<mnc> - For bundled distributions for specific network providers
      * /system/<package>/distribution/<mcc>       - For bundled distributions for specific countries
      * /system/<package>/distribution/default     - For bundled distributions with no matching mcc/mnc
      * /system/<package>/distribution             - Default non-bundled system distribution
      */
     private static String[] getSystemDistributionDirectories(Context context) {
-        final String baseDirectory = "/system/" + context.getPackageName() + "/distribution";
+        final String systemPropertyBaseDirectory = getDistributionDirectoryFromSystemProperty();
+        final String baseDirectory;
+        if (systemPropertyBaseDirectory != null) {
+            baseDirectory = systemPropertyBaseDirectory + context.getPackageName() + "/distribution";
+        } else {
+            baseDirectory = "/system/" + context.getPackageName() + "/distribution";
+        }
         return getDistributionDirectoriesFromBaseDirectory(context, baseDirectory);
     }
 
     /**
      * Get a list of data distribution folder candidates.
      *
      * <dataDir>/distribution/<mcc>/<mnc> - For bundled distributions for specific network providers
      * <dataDir>/distribution/<mcc>       - For bundled distributions for specific countries