Merge "Always-on app VPNs"
This commit is contained in:
@@ -17,6 +17,7 @@ package android.net;
|
|||||||
|
|
||||||
import static com.android.internal.util.Preconditions.checkNotNull;
|
import static com.android.internal.util.Preconditions.checkNotNull;
|
||||||
|
|
||||||
|
import android.annotation.Nullable;
|
||||||
import android.annotation.SdkConstant;
|
import android.annotation.SdkConstant;
|
||||||
import android.annotation.SdkConstant.SdkConstantType;
|
import android.annotation.SdkConstant.SdkConstantType;
|
||||||
import android.annotation.SystemApi;
|
import android.annotation.SystemApi;
|
||||||
@@ -685,6 +686,47 @@ public class ConnectivityManager {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Configures an always-on VPN connection through a specific application.
|
||||||
|
* This connection is automatically granted and persisted after a reboot.
|
||||||
|
*
|
||||||
|
* <p>The designated package should declare a {@link VpnService} in its
|
||||||
|
* manifest guarded by {@link android.Manifest.permission.BIND_VPN_SERVICE},
|
||||||
|
* otherwise the call will fail.
|
||||||
|
*
|
||||||
|
* @param userId The identifier of the user to set an always-on VPN for.
|
||||||
|
* @param vpnPackage The package name for an installed VPN app on the device, or {@code null}
|
||||||
|
* to remove an existing always-on VPN configuration.
|
||||||
|
|
||||||
|
* @return {@code true} if the package is set as always-on VPN controller;
|
||||||
|
* {@code false} otherwise.
|
||||||
|
* @hide
|
||||||
|
*/
|
||||||
|
public boolean setAlwaysOnVpnPackageForUser(int userId, @Nullable String vpnPackage) {
|
||||||
|
try {
|
||||||
|
return mService.setAlwaysOnVpnPackage(userId, vpnPackage);
|
||||||
|
} catch (RemoteException e) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the package name of the currently set always-on VPN application.
|
||||||
|
* If there is no always-on VPN set, or the VPN is provided by the system instead
|
||||||
|
* of by an app, {@code null} will be returned.
|
||||||
|
*
|
||||||
|
* @return Package name of VPN controller responsible for always-on VPN,
|
||||||
|
* or {@code null} if none is set.
|
||||||
|
* @hide
|
||||||
|
*/
|
||||||
|
public String getAlwaysOnVpnPackageForUser(int userId) {
|
||||||
|
try {
|
||||||
|
return mService.getAlwaysOnVpnPackage(userId);
|
||||||
|
} catch (RemoteException e) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns details about the currently active default data network
|
* Returns details about the currently active default data network
|
||||||
* for a given uid. This is for internal use only to avoid spying
|
* for a given uid. This is for internal use only to avoid spying
|
||||||
|
|||||||
@@ -117,6 +117,8 @@ interface IConnectivityManager
|
|||||||
VpnInfo[] getAllVpnInfo();
|
VpnInfo[] getAllVpnInfo();
|
||||||
|
|
||||||
boolean updateLockdownVpn();
|
boolean updateLockdownVpn();
|
||||||
|
boolean setAlwaysOnVpnPackage(int userId, String packageName);
|
||||||
|
String getAlwaysOnVpnPackage(int userId);
|
||||||
|
|
||||||
int checkMobileProvisioning(int suggestedTimeOutMs);
|
int checkMobileProvisioning(int suggestedTimeOutMs);
|
||||||
|
|
||||||
|
|||||||
@@ -1568,12 +1568,11 @@ public class ConnectivityService extends IConnectivityManager.Stub
|
|||||||
// load the global proxy at startup
|
// load the global proxy at startup
|
||||||
mHandler.sendMessage(mHandler.obtainMessage(EVENT_APPLY_GLOBAL_HTTP_PROXY));
|
mHandler.sendMessage(mHandler.obtainMessage(EVENT_APPLY_GLOBAL_HTTP_PROXY));
|
||||||
|
|
||||||
// Try bringing up tracker, but if KeyStore isn't ready yet, wait
|
// Try bringing up tracker, but KeyStore won't be ready yet for secondary users so wait
|
||||||
// for user to unlock device.
|
// for user to unlock device too.
|
||||||
if (!updateLockdownVpn()) {
|
updateLockdownVpn();
|
||||||
final IntentFilter filter = new IntentFilter(Intent.ACTION_USER_PRESENT);
|
final IntentFilter filter = new IntentFilter(Intent.ACTION_USER_PRESENT);
|
||||||
mContext.registerReceiver(mUserPresentReceiver, filter);
|
mContext.registerReceiverAsUser(mUserPresentReceiver, UserHandle.ALL, filter, null, null);
|
||||||
}
|
|
||||||
|
|
||||||
// Configure whether mobile data is always on.
|
// Configure whether mobile data is always on.
|
||||||
mHandler.sendMessage(mHandler.obtainMessage(EVENT_CONFIGURE_MOBILE_DATA_ALWAYS_ON));
|
mHandler.sendMessage(mHandler.obtainMessage(EVENT_CONFIGURE_MOBILE_DATA_ALWAYS_ON));
|
||||||
@@ -1586,10 +1585,16 @@ public class ConnectivityService extends IConnectivityManager.Stub
|
|||||||
private BroadcastReceiver mUserPresentReceiver = new BroadcastReceiver() {
|
private BroadcastReceiver mUserPresentReceiver = new BroadcastReceiver() {
|
||||||
@Override
|
@Override
|
||||||
public void onReceive(Context context, Intent intent) {
|
public void onReceive(Context context, Intent intent) {
|
||||||
|
// User that sent this intent = user that was just unlocked
|
||||||
|
final int unlockedUser = getSendingUserId();
|
||||||
|
|
||||||
// Try creating lockdown tracker, since user present usually means
|
// Try creating lockdown tracker, since user present usually means
|
||||||
// unlocked keystore.
|
// unlocked keystore.
|
||||||
if (updateLockdownVpn()) {
|
if (mUserManager.getUserInfo(unlockedUser).isPrimary() &&
|
||||||
mContext.unregisterReceiver(this);
|
LockdownVpnTracker.isEnabled()) {
|
||||||
|
updateLockdownVpn();
|
||||||
|
} else {
|
||||||
|
updateAlwaysOnVpn(unlockedUser);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@@ -3258,6 +3263,76 @@ public class ConnectivityService extends IConnectivityManager.Stub
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets up or tears down the always-on VPN for user {@param user} as appropriate.
|
||||||
|
*
|
||||||
|
* @return {@code false} in case of errors; {@code true} otherwise.
|
||||||
|
*/
|
||||||
|
private boolean updateAlwaysOnVpn(int user) {
|
||||||
|
final String lockdownPackage = getAlwaysOnVpnPackage(user);
|
||||||
|
if (lockdownPackage == null) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create an intent to start the VPN service declared in the app's manifest.
|
||||||
|
Intent serviceIntent = new Intent(VpnConfig.SERVICE_INTERFACE);
|
||||||
|
serviceIntent.setPackage(lockdownPackage);
|
||||||
|
|
||||||
|
try {
|
||||||
|
return mContext.startServiceAsUser(serviceIntent, UserHandle.of(user)) != null;
|
||||||
|
} catch (RuntimeException e) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean setAlwaysOnVpnPackage(int userId, String packageName) {
|
||||||
|
enforceConnectivityInternalPermission();
|
||||||
|
enforceCrossUserPermission(userId);
|
||||||
|
|
||||||
|
// Can't set always-on VPN if legacy VPN is already in lockdown mode.
|
||||||
|
if (LockdownVpnTracker.isEnabled()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// If the current VPN package is the same as the new one, this is a no-op
|
||||||
|
final String oldPackage = getAlwaysOnVpnPackage(userId);
|
||||||
|
if (TextUtils.equals(oldPackage, packageName)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
synchronized (mVpns) {
|
||||||
|
Vpn vpn = mVpns.get(userId);
|
||||||
|
if (vpn == null) {
|
||||||
|
Slog.w(TAG, "User " + userId + " has no Vpn configuration");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (!vpn.setAlwaysOnPackage(packageName)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (!updateAlwaysOnVpn(userId)) {
|
||||||
|
vpn.setAlwaysOnPackage(null);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getAlwaysOnVpnPackage(int userId) {
|
||||||
|
enforceConnectivityInternalPermission();
|
||||||
|
enforceCrossUserPermission(userId);
|
||||||
|
|
||||||
|
synchronized (mVpns) {
|
||||||
|
Vpn vpn = mVpns.get(userId);
|
||||||
|
if (vpn == null) {
|
||||||
|
Slog.w(TAG, "User " + userId + " has no Vpn configuration");
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return vpn.getAlwaysOnPackage();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int checkMobileProvisioning(int suggestedTimeOutMs) {
|
public int checkMobileProvisioning(int suggestedTimeOutMs) {
|
||||||
// TODO: Remove? Any reason to trigger a provisioning check?
|
// TODO: Remove? Any reason to trigger a provisioning check?
|
||||||
|
|||||||
Reference in New Issue
Block a user