Bug #1355870 - Allow a system preference to determine distribution dir. r=nalexander draft
authorMichael Kaply <mozilla@kaply.com>
Thu, 13 Apr 2017 14:14:18 -0500
changeset 562253 04115195be6d49861621f11060ce05c59053d277
parent 557470 e3b4e04987c74a7e68b045c867f94c6f9bc1a5a6
child 624220 f7b4ca58f596d459de3e197ac4c3f43d74e70087
push id54005
push usermozilla@kaply.com
push dateThu, 13 Apr 2017 19:17:10 +0000
reviewersnalexander
bugs1355870
milestone55.0a1
Bug #1355870 - Allow a system preference to determine distribution dir. r=nalexander MozReview-Commit-ID: GmD6CGsKX5h
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;
@@ -83,17 +84,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
@@ -930,25 +934,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