From dc48356147fd55cafb1dbc8315b3f581c4274292 Mon Sep 17 00:00:00 2001 From: Remi NGUYEN VAN Date: Mon, 4 Feb 2019 11:32:20 +0900 Subject: [PATCH] Add API for NetworkStack to start captive portal Endpoints protected with INTERACT_ACROSS_USERS_FULL, such as startActivityAsUser, should only be used by modules signed with the platform cert. The NetworkStack needs to have the system server start the application so this restriction can be applied. Bug: 123846255 Test: flashed, captive portal works from primary and secondary user Change-Id: Ib3e427b3fd03ced80c02985e795f79b096a2ec9a --- api/system-current.txt | 1 + api/test-current.txt | 1 + .../java/android/net/ConnectivityManager.java | 19 +++++++++++++++++++ .../android/net/IConnectivityManager.aidl | 2 ++ .../server/connectivity/NetworkMonitor.java | 19 +++++++++---------- .../android/server/ConnectivityService.java | 19 +++++++++++++++++++ 6 files changed, 51 insertions(+), 10 deletions(-) diff --git a/api/system-current.txt b/api/system-current.txt index 8a7cf2e8bdde9..6cb974fb81dbf 100644 --- a/api/system-current.txt +++ b/api/system-current.txt @@ -3074,6 +3074,7 @@ package android.net { method @RequiresPermission(android.Manifest.permission.TETHER_PRIVILEGED) public void getLatestTetheringEntitlementValue(int, boolean, @NonNull android.net.ConnectivityManager.TetheringEntitlementValueListener, @Nullable android.os.Handler); method @RequiresPermission(anyOf={android.Manifest.permission.TETHER_PRIVILEGED, android.Manifest.permission.WRITE_SETTINGS}) public boolean isTetheringSupported(); method @RequiresPermission(anyOf={"android.permission.NETWORK_SETTINGS", android.Manifest.permission.NETWORK_SETUP_WIZARD, "android.permission.NETWORK_STACK"}) public void setAirplaneMode(boolean); + method @RequiresPermission(android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK) public void startCaptivePortalApp(android.os.Bundle); method @RequiresPermission(android.Manifest.permission.TETHER_PRIVILEGED) public void startTethering(int, boolean, android.net.ConnectivityManager.OnStartTetheringCallback); method @RequiresPermission(android.Manifest.permission.TETHER_PRIVILEGED) public void startTethering(int, boolean, android.net.ConnectivityManager.OnStartTetheringCallback, android.os.Handler); method @RequiresPermission(android.Manifest.permission.TETHER_PRIVILEGED) public void stopTethering(int); diff --git a/api/test-current.txt b/api/test-current.txt index 34c8f6ef5ecea..01127249c1fc5 100644 --- a/api/test-current.txt +++ b/api/test-current.txt @@ -608,6 +608,7 @@ package android.net { } public class ConnectivityManager { + method @RequiresPermission(android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK) public void startCaptivePortalApp(android.os.Bundle); field public static final String EXTRA_CAPTIVE_PORTAL_PROBE_SPEC = "android.net.extra.CAPTIVE_PORTAL_PROBE_SPEC"; field public static final String EXTRA_CAPTIVE_PORTAL_USER_AGENT = "android.net.extra.CAPTIVE_PORTAL_USER_AGENT"; } diff --git a/core/java/android/net/ConnectivityManager.java b/core/java/android/net/ConnectivityManager.java index 2ea23ec6b5c8b..28af025ad2a9e 100644 --- a/core/java/android/net/ConnectivityManager.java +++ b/core/java/android/net/ConnectivityManager.java @@ -3866,6 +3866,25 @@ public class ConnectivityManager { } } + /** + * Requests that the system open the captive portal app with the specified extras. + * + *

This endpoint is exclusively for use by the NetworkStack and is protected by the + * corresponding permission. + * @param appExtras Extras to include in the app start intent. + * @hide + */ + @SystemApi + @TestApi + @RequiresPermission(NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK) + public void startCaptivePortalApp(Bundle appExtras) { + try { + mService.startCaptivePortalAppInternal(appExtras); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + /** * Determine whether the device is configured to avoid bad wifi. * @hide diff --git a/core/java/android/net/IConnectivityManager.aidl b/core/java/android/net/IConnectivityManager.aidl index 78fafebc4f37d..ea2f6d24d5ae7 100644 --- a/core/java/android/net/IConnectivityManager.aidl +++ b/core/java/android/net/IConnectivityManager.aidl @@ -27,6 +27,7 @@ import android.net.NetworkQuotaInfo; import android.net.NetworkRequest; import android.net.NetworkState; import android.net.ProxyInfo; +import android.os.Bundle; import android.os.IBinder; import android.os.Messenger; import android.os.ParcelFileDescriptor; @@ -167,6 +168,7 @@ interface IConnectivityManager void setAcceptUnvalidated(in Network network, boolean accept, boolean always); void setAvoidUnvalidated(in Network network); void startCaptivePortalApp(in Network network); + void startCaptivePortalAppInternal(in Bundle appExtras); boolean getAvoidBadWifi(); int getMultipathPreference(in Network Network); diff --git a/packages/NetworkStack/src/com/android/server/connectivity/NetworkMonitor.java b/packages/NetworkStack/src/com/android/server/connectivity/NetworkMonitor.java index dbffa6d6bcf2c..0d6d080b6dc2f 100644 --- a/packages/NetworkStack/src/com/android/server/connectivity/NetworkMonitor.java +++ b/packages/NetworkStack/src/com/android/server/connectivity/NetworkMonitor.java @@ -61,6 +61,7 @@ import android.net.util.SharedLog; import android.net.util.Stopwatch; import android.net.wifi.WifiInfo; import android.net.wifi.WifiManager; +import android.os.Bundle; import android.os.Message; import android.os.RemoteException; import android.os.SystemClock; @@ -674,11 +675,11 @@ public class NetworkMonitor extends StateMachine { public boolean processMessage(Message message) { switch (message.what) { case CMD_LAUNCH_CAPTIVE_PORTAL_APP: - final Intent intent = new Intent( - ConnectivityManager.ACTION_CAPTIVE_PORTAL_SIGN_IN); + final Bundle appExtras = new Bundle(); // OneAddressPerFamilyNetwork is not parcelable across processes. - intent.putExtra(ConnectivityManager.EXTRA_NETWORK, new Network(mNetwork)); - intent.putExtra(ConnectivityManager.EXTRA_CAPTIVE_PORTAL, + appExtras.putParcelable( + ConnectivityManager.EXTRA_NETWORK, new Network(mNetwork)); + appExtras.putParcelable(ConnectivityManager.EXTRA_CAPTIVE_PORTAL, new CaptivePortal(new ICaptivePortal.Stub() { @Override public void appResponse(int response) { @@ -700,16 +701,14 @@ public class NetworkMonitor extends StateMachine { } })); final CaptivePortalProbeResult probeRes = mLastPortalProbeResult; - intent.putExtra(EXTRA_CAPTIVE_PORTAL_URL, probeRes.detectUrl); + appExtras.putString(EXTRA_CAPTIVE_PORTAL_URL, probeRes.detectUrl); if (probeRes.probeSpec != null) { final String encodedSpec = probeRes.probeSpec.getEncodedSpec(); - intent.putExtra(EXTRA_CAPTIVE_PORTAL_PROBE_SPEC, encodedSpec); + appExtras.putString(EXTRA_CAPTIVE_PORTAL_PROBE_SPEC, encodedSpec); } - intent.putExtra(ConnectivityManager.EXTRA_CAPTIVE_PORTAL_USER_AGENT, + appExtras.putString(ConnectivityManager.EXTRA_CAPTIVE_PORTAL_USER_AGENT, mCaptivePortalUserAgent); - intent.setFlags( - Intent.FLAG_ACTIVITY_BROUGHT_TO_FRONT | Intent.FLAG_ACTIVITY_NEW_TASK); - mContext.startActivityAsUser(intent, UserHandle.CURRENT); + mCm.startCaptivePortalApp(appExtras); return HANDLED; default: return NOT_HANDLED; diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java index b98d7a194dfe9..ff44cbeada383 100644 --- a/services/core/java/com/android/server/ConnectivityService.java +++ b/services/core/java/com/android/server/ConnectivityService.java @@ -3230,6 +3230,25 @@ public class ConnectivityService extends IConnectivityManager.Stub }); } + /** + * NetworkStack endpoint to start the captive portal app. The NetworkStack needs to use this + * endpoint as it does not have INTERACT_ACROSS_USERS_FULL itself. + * @param appExtras Bundle to use as intent extras for the captive portal application. + * Must be treated as opaque to avoid preventing the captive portal app to + * update its arguments. + */ + @Override + public void startCaptivePortalAppInternal(Bundle appExtras) { + mContext.checkCallingOrSelfPermission(NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK); + + final Intent appIntent = new Intent(ConnectivityManager.ACTION_CAPTIVE_PORTAL_SIGN_IN); + appIntent.putExtras(appExtras); + appIntent.setFlags(Intent.FLAG_ACTIVITY_BROUGHT_TO_FRONT | Intent.FLAG_ACTIVITY_NEW_TASK); + + Binder.withCleanCallingIdentity(() -> + mContext.startActivityAsUser(appIntent, UserHandle.CURRENT)); + } + public boolean avoidBadWifi() { return mMultinetworkPolicyTracker.getAvoidBadWifi(); }