Implement multi-network downloads
Robin Lee [Thu, 24 Mar 2016 12:02:50 +0000 (12:02 +0000)]
Downloads should use the default network for the caller. This prevents
applications from, for example, bypassing VPN by routing all requests
through the DownloadProvider.

Bug: 27074270
Change-Id: I7830226dd2910757d3a5c78f373330f84637ccfa

src/com/android/providers/downloads/DownloadThread.java
src/com/android/providers/downloads/RealSystemFacade.java
src/com/android/providers/downloads/SystemFacade.java
tests/src/com/android/providers/downloads/FakeSystemFacade.java

index 65142db..8d51909 100644 (file)
@@ -45,6 +45,7 @@ import android.drm.DrmManagerClient;
 import android.drm.DrmOutputStream;
 import android.net.ConnectivityManager;
 import android.net.INetworkPolicyListener;
+import android.net.Network;
 import android.net.NetworkInfo;
 import android.net.NetworkPolicyManager;
 import android.net.TrafficStats;
@@ -351,6 +352,13 @@ public class DownloadThread implements Runnable {
             throw new StopRequestException(STATUS_BAD_REQUEST, e);
         }
 
+        final Network network = mSystemFacade.getActiveNetwork(mInfo.mUid);
+        if (network == null) {
+            throw new StopRequestException(Downloads.Impl.STATUS_WAITING_FOR_NETWORK,
+                    "no network associated with requesting UID");
+        }
+        logDebug("Using network: " + network);
+
         boolean cleartextTrafficPermitted = mSystemFacade.isCleartextTrafficPermitted(mInfo.mUid);
         int redirectionCount = 0;
         while (redirectionCount++ < Constants.MAX_REDIRECTS) {
@@ -367,7 +375,7 @@ public class DownloadThread implements Runnable {
             HttpURLConnection conn = null;
             try {
                 checkConnectivity();
-                conn = (HttpURLConnection) url.openConnection();
+                conn = (HttpURLConnection) network.openConnection(url);
                 conn.setInstanceFollowRedirects(false);
                 conn.setConnectTimeout(DEFAULT_TIMEOUT);
                 conn.setReadTimeout(DEFAULT_TIMEOUT);
index b3f170f..48df2a0 100644 (file)
@@ -26,6 +26,7 @@ import android.content.pm.PackageInfo;
 import android.content.pm.PackageManager;
 import android.content.pm.PackageManager.NameNotFoundException;
 import android.net.ConnectivityManager;
+import android.net.Network;
 import android.net.NetworkInfo;
 import android.telephony.TelephonyManager;
 import android.util.Log;
@@ -59,6 +60,13 @@ class RealSystemFacade implements SystemFacade {
     }
 
     @Override
+    public Network getActiveNetwork(int uid) {
+        ConnectivityManager connectivity =
+                (ConnectivityManager) mContext.getSystemService(Context.CONNECTIVITY_SERVICE);
+        return connectivity.getActiveNetworkForUid(uid);
+    }
+
+    @Override
     public boolean isActiveNetworkMetered() {
         final ConnectivityManager conn = ConnectivityManager.from(mContext);
         return conn.isActiveNetworkMetered();
index 83fc7a6..7f97b91 100644 (file)
@@ -18,6 +18,7 @@ package com.android.providers.downloads;
 
 import android.content.Intent;
 import android.content.pm.PackageManager.NameNotFoundException;
+import android.net.Network;
 import android.net.NetworkInfo;
 
 interface SystemFacade {
@@ -32,6 +33,8 @@ interface SystemFacade {
      */
     public NetworkInfo getActiveNetworkInfo(int uid);
 
+    public Network getActiveNetwork(int uid);
+
     public boolean isActiveNetworkMetered();
 
     /**
index 7581e6f..af5482e 100644 (file)
@@ -3,6 +3,7 @@ package com.android.providers.downloads;
 import android.content.Intent;
 import android.content.pm.PackageManager.NameNotFoundException;
 import android.net.ConnectivityManager;
+import android.net.Network;
 import android.net.NetworkInfo;
 import android.net.NetworkInfo.DetailedState;
 
@@ -10,6 +11,7 @@ import java.util.ArrayList;
 import java.util.List;
 public class FakeSystemFacade implements SystemFacade {
     long mTimeMillis = 0;
+    Network mActiveNetwork = null;
     Integer mActiveNetworkType = ConnectivityManager.TYPE_WIFI;
     boolean mIsRoaming = false;
     boolean mIsMetered = false;
@@ -43,6 +45,11 @@ public class FakeSystemFacade implements SystemFacade {
     }
 
     @Override
+    public Network getActiveNetwork(int uid) {
+        return mActiveNetwork;
+    }
+
+    @Override
     public NetworkInfo getActiveNetworkInfo(int uid) {
         if (mActiveNetworkType == null) {
             return null;