Merge "resolve merge conflicts of 943187668c to oc-dev-plus-aosp" into oc-dev-plus-aosp

This commit is contained in:
Robin Lee
2017-03-30 16:49:53 +00:00
committed by Android (Google) Code Review
3 changed files with 133 additions and 57 deletions

View File

@@ -3740,8 +3740,6 @@ public class ConnectivityService extends IConnectivityManager.Stub
vpn.setAlwaysOnPackage(null, false); vpn.setAlwaysOnPackage(null, false);
return false; return false;
} }
vpn.saveAlwaysOnPackage();
} }
return true; return true;
} }
@@ -3902,15 +3900,6 @@ public class ConnectivityService extends IConnectivityManager.Stub
} }
userVpn = new Vpn(mHandler.getLooper(), mContext, mNetd, userId); userVpn = new Vpn(mHandler.getLooper(), mContext, mNetd, userId);
mVpns.put(userId, userVpn); mVpns.put(userId, userVpn);
final ContentResolver cr = mContext.getContentResolver();
String alwaysOnPackage = Settings.Secure.getStringForUser(cr,
Settings.Secure.ALWAYS_ON_VPN_APP, userId);
final boolean alwaysOnLockdown = Settings.Secure.getIntForUser(cr,
Settings.Secure.ALWAYS_ON_VPN_LOCKDOWN, /* default */ 0, userId) != 0;
if (alwaysOnPackage != null) {
userVpn.setAlwaysOnPackage(alwaysOnPackage, alwaysOnLockdown);
}
} }
if (mUserManager.getUserInfo(userId).isPrimary() && LockdownVpnTracker.isEnabled()) { if (mUserManager.getUserInfo(userId).isPrimary() && LockdownVpnTracker.isEnabled()) {
updateLockdownVpn(); updateLockdownVpn();

View File

@@ -32,7 +32,6 @@ import android.app.NotificationManager;
import android.app.PendingIntent; import android.app.PendingIntent;
import android.content.BroadcastReceiver; import android.content.BroadcastReceiver;
import android.content.ComponentName; import android.content.ComponentName;
import android.content.ContentResolver;
import android.content.Context; import android.content.Context;
import android.content.Intent; import android.content.Intent;
import android.content.IntentFilter; import android.content.IntentFilter;
@@ -139,6 +138,7 @@ public class Vpn {
private NetworkAgent mNetworkAgent; private NetworkAgent mNetworkAgent;
private final Looper mLooper; private final Looper mLooper;
private final NetworkCapabilities mNetworkCapabilities; private final NetworkCapabilities mNetworkCapabilities;
private final SystemServices mSystemServices;
/** /**
* Whether to keep the connection active after rebooting, or upgrading or reinstalling. This * Whether to keep the connection active after rebooting, or upgrading or reinstalling. This
@@ -206,7 +206,7 @@ public class Vpn {
final boolean isPackageRemoved = !intent.getBooleanExtra( final boolean isPackageRemoved = !intent.getBooleanExtra(
Intent.EXTRA_REPLACING, false); Intent.EXTRA_REPLACING, false);
if (isPackageRemoved) { if (isPackageRemoved) {
setAndSaveAlwaysOnPackage(null, false); setAlwaysOnPackage(null, false);
} }
break; break;
} }
@@ -217,11 +217,18 @@ public class Vpn {
private boolean mIsPackageIntentReceiverRegistered = false; private boolean mIsPackageIntentReceiverRegistered = false;
public Vpn(Looper looper, Context context, INetworkManagementService netService, public Vpn(Looper looper, Context context, INetworkManagementService netService,
int userHandle) { @UserIdInt int userHandle) {
this(looper, context, netService, userHandle, new SystemServices(context));
}
@VisibleForTesting
protected Vpn(Looper looper, Context context, INetworkManagementService netService,
int userHandle, SystemServices systemServices) {
mContext = context; mContext = context;
mNetd = netService; mNetd = netService;
mUserHandle = userHandle; mUserHandle = userHandle;
mLooper = looper; mLooper = looper;
mSystemServices = systemServices;
mPackage = VpnConfig.LEGACY_VPN; mPackage = VpnConfig.LEGACY_VPN;
mOwnerUID = getAppUid(mPackage, mUserHandle); mOwnerUID = getAppUid(mPackage, mUserHandle);
@@ -237,6 +244,8 @@ public class Vpn {
mNetworkCapabilities = new NetworkCapabilities(); mNetworkCapabilities = new NetworkCapabilities();
mNetworkCapabilities.addTransportType(NetworkCapabilities.TRANSPORT_VPN); mNetworkCapabilities.addTransportType(NetworkCapabilities.TRANSPORT_VPN);
mNetworkCapabilities.removeCapability(NetworkCapabilities.NET_CAPABILITY_NOT_VPN); mNetworkCapabilities.removeCapability(NetworkCapabilities.NET_CAPABILITY_NOT_VPN);
loadAlwaysOnPackage();
} }
/** /**
@@ -275,6 +284,26 @@ public class Vpn {
*/ */
public synchronized boolean setAlwaysOnPackage(String packageName, boolean lockdown) { public synchronized boolean setAlwaysOnPackage(String packageName, boolean lockdown) {
enforceControlPermissionOrInternalCaller(); enforceControlPermissionOrInternalCaller();
if (setAlwaysOnPackageInternal(packageName, lockdown)) {
saveAlwaysOnPackage();
return true;
}
return false;
}
/**
* Configures an always-on VPN connection through a specific application, the same as
* {@link #setAlwaysOnPackage}.
*
* Does not perform permission checks. Does not persist any of the changes to storage.
*
* @param packageName the package to designate as always-on VPN supplier.
* @param lockdown whether to prevent traffic outside of a VPN, for example while connecting.
* @return {@code true} if the package has been set as always-on, {@code false} otherwise.
*/
@GuardedBy("this")
private boolean setAlwaysOnPackageInternal(String packageName, boolean lockdown) {
if (VpnConfig.LEGACY_VPN.equals(packageName)) { if (VpnConfig.LEGACY_VPN.equals(packageName)) {
Log.w(TAG, "Not setting legacy VPN \"" + packageName + "\" as always-on."); Log.w(TAG, "Not setting legacy VPN \"" + packageName + "\" as always-on.");
return false; return false;
@@ -347,13 +376,13 @@ public class Vpn {
/** /**
* Save the always-on package and lockdown config into Settings.Secure * Save the always-on package and lockdown config into Settings.Secure
*/ */
public synchronized void saveAlwaysOnPackage() { @GuardedBy("this")
private void saveAlwaysOnPackage() {
final long token = Binder.clearCallingIdentity(); final long token = Binder.clearCallingIdentity();
try { try {
final ContentResolver cr = mContext.getContentResolver(); mSystemServices.settingsSecurePutStringForUser(Settings.Secure.ALWAYS_ON_VPN_APP,
Settings.Secure.putStringForUser(cr, Settings.Secure.ALWAYS_ON_VPN_APP,
getAlwaysOnPackage(), mUserHandle); getAlwaysOnPackage(), mUserHandle);
Settings.Secure.putIntForUser(cr, Settings.Secure.ALWAYS_ON_VPN_LOCKDOWN, mSystemServices.settingsSecurePutIntForUser(Settings.Secure.ALWAYS_ON_VPN_LOCKDOWN,
(mLockdown ? 1 : 0), mUserHandle); (mLockdown ? 1 : 0), mUserHandle);
} finally { } finally {
Binder.restoreCallingIdentity(token); Binder.restoreCallingIdentity(token);
@@ -361,18 +390,19 @@ public class Vpn {
} }
/** /**
* Set and save always-on package and lockdown config * Load the always-on package and lockdown config from Settings.Secure
* @see Vpn#setAlwaysOnPackage(String, boolean)
* @see Vpn#saveAlwaysOnPackage()
*
* @return result of Vpn#setAndSaveAlwaysOnPackage(String, boolean)
*/ */
private synchronized boolean setAndSaveAlwaysOnPackage(String packageName, boolean lockdown) { @GuardedBy("this")
if (setAlwaysOnPackage(packageName, lockdown)) { private void loadAlwaysOnPackage() {
saveAlwaysOnPackage(); final long token = Binder.clearCallingIdentity();
return true; try {
} else { final String alwaysOnPackage = mSystemServices.settingsSecureGetStringForUser(
return false; Settings.Secure.ALWAYS_ON_VPN_APP, mUserHandle);
final boolean alwaysOnLockdown = mSystemServices.settingsSecureGetIntForUser(
Settings.Secure.ALWAYS_ON_VPN_LOCKDOWN, 0 /*default*/, mUserHandle) != 0;
setAlwaysOnPackageInternal(alwaysOnPackage, alwaysOnLockdown);
} finally {
Binder.restoreCallingIdentity(token);
} }
} }
@@ -1276,11 +1306,7 @@ public class Vpn {
private void updateAlwaysOnNotification(DetailedState networkState) { private void updateAlwaysOnNotification(DetailedState networkState) {
final boolean visible = (mAlwaysOn && networkState != DetailedState.CONNECTED); final boolean visible = (mAlwaysOn && networkState != DetailedState.CONNECTED);
updateAlwaysOnNotificationInternal(visible);
}
@VisibleForTesting
protected void updateAlwaysOnNotificationInternal(boolean visible) {
final UserHandle user = UserHandle.of(mUserHandle); final UserHandle user = UserHandle.of(mUserHandle);
final long token = Binder.clearCallingIdentity(); final long token = Binder.clearCallingIdentity();
try { try {
@@ -1290,10 +1316,8 @@ public class Vpn {
return; return;
} }
final Intent intent = new Intent(Settings.ACTION_VPN_SETTINGS); final Intent intent = new Intent(Settings.ACTION_VPN_SETTINGS);
final PendingIntent configIntent = PendingIntent.getActivityAsUser( final PendingIntent configIntent = mSystemServices.pendingIntentGetActivityAsUser(
mContext, /* request */ 0, intent, intent, PendingIntent.FLAG_IMMUTABLE | PendingIntent.FLAG_UPDATE_CURRENT, user);
PendingIntent.FLAG_IMMUTABLE | PendingIntent.FLAG_UPDATE_CURRENT,
null, user);
final Notification.Builder builder = final Notification.Builder builder =
new Notification.Builder(mContext, SystemNotificationChannels.VPN) new Notification.Builder(mContext, SystemNotificationChannels.VPN)
.setSmallIcon(R.drawable.vpn_connected) .setSmallIcon(R.drawable.vpn_connected)
@@ -1310,6 +1334,58 @@ public class Vpn {
} }
} }
/**
* Facade for system service calls that change, or depend on, state outside of
* {@link ConnectivityService} and have hard-to-mock interfaces.
*
* @see com.android.server.connectivity.VpnTest
*/
@VisibleForTesting
public static class SystemServices {
private final Context mContext;
public SystemServices(@NonNull Context context) {
mContext = context;
}
/**
* @see PendingIntent#getActivityAsUser()
*/
public PendingIntent pendingIntentGetActivityAsUser(
Intent intent, int flags, UserHandle user) {
return PendingIntent.getActivityAsUser(mContext, 0 /*request*/, intent, flags,
null /*options*/, user);
}
/**
* @see Settings.Secure#putStringForUser
*/
public void settingsSecurePutStringForUser(String key, String value, int userId) {
Settings.Secure.putStringForUser(mContext.getContentResolver(), key, value, userId);
}
/**
* @see Settings.Secure#putIntForUser
*/
public void settingsSecurePutIntForUser(String key, int value, int userId) {
Settings.Secure.putIntForUser(mContext.getContentResolver(), key, value, userId);
}
/**
* @see Settings.Secure#getStringForUser
*/
public String settingsSecureGetStringForUser(String key, int userId) {
return Settings.Secure.getStringForUser(mContext.getContentResolver(), key, userId);
}
/**
* @see Settings.Secure#getIntForUser
*/
public int settingsSecureGetIntForUser(String key, int def, int userId) {
return Settings.Secure.getIntForUser(mContext.getContentResolver(), key, def, userId);
}
}
private native int jniCreate(int mtu); private native int jniCreate(int mtu);
private native String jniGetName(int tun); private native String jniGetName(int tun);
private native int jniSetAddresses(String interfaze, String addresses); private native int jniSetAddresses(String interfaze, String addresses);

View File

@@ -27,10 +27,12 @@ import android.annotation.UserIdInt;
import android.app.AppOpsManager; import android.app.AppOpsManager;
import android.app.NotificationManager; import android.app.NotificationManager;
import android.content.Context; import android.content.Context;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager; import android.content.pm.PackageManager;
import android.content.pm.UserInfo; import android.content.pm.UserInfo;
import android.net.NetworkInfo.DetailedState; import android.net.NetworkInfo.DetailedState;
import android.net.UidRange; import android.net.UidRange;
import android.os.Build;
import android.os.INetworkManagementService; import android.os.INetworkManagementService;
import android.os.Looper; import android.os.Looper;
import android.os.UserHandle; import android.os.UserHandle;
@@ -45,6 +47,7 @@ import java.util.Arrays;
import java.util.Map; import java.util.Map;
import java.util.Set; import java.util.Set;
import org.mockito.Answers;
import org.mockito.ArgumentCaptor; import org.mockito.ArgumentCaptor;
import org.mockito.InOrder; import org.mockito.InOrder;
import org.mockito.Mock; import org.mockito.Mock;
@@ -87,12 +90,13 @@ public class VpnTest extends AndroidTestCase {
} }
} }
@Mock private Context mContext; @Mock(answer = Answers.RETURNS_DEEP_STUBS) private Context mContext;
@Mock private UserManager mUserManager; @Mock private UserManager mUserManager;
@Mock private PackageManager mPackageManager; @Mock private PackageManager mPackageManager;
@Mock private INetworkManagementService mNetService; @Mock private INetworkManagementService mNetService;
@Mock private AppOpsManager mAppOps; @Mock private AppOpsManager mAppOps;
@Mock private NotificationManager mNotificationManager; @Mock private NotificationManager mNotificationManager;
@Mock private Vpn.SystemServices mSystemServices;
@Override @Override
public void setUp() throws Exception { public void setUp() throws Exception {
@@ -104,6 +108,12 @@ public class VpnTest extends AndroidTestCase {
when(mContext.getSystemService(eq(Context.APP_OPS_SERVICE))).thenReturn(mAppOps); when(mContext.getSystemService(eq(Context.APP_OPS_SERVICE))).thenReturn(mAppOps);
when(mContext.getSystemService(eq(Context.NOTIFICATION_SERVICE))) when(mContext.getSystemService(eq(Context.NOTIFICATION_SERVICE)))
.thenReturn(mNotificationManager); .thenReturn(mNotificationManager);
// Used by {@link Notification.Builder}
ApplicationInfo applicationInfo = new ApplicationInfo();
applicationInfo.targetSdkVersion = Build.VERSION_CODES.CUR_DEVELOPMENT;
when(mContext.getApplicationInfo()).thenReturn(applicationInfo);
doNothing().when(mNetService).registerObserver(any()); doNothing().when(mNetService).registerObserver(any());
} }
@@ -111,7 +121,7 @@ public class VpnTest extends AndroidTestCase {
public void testRestrictedProfilesAreAddedToVpn() { public void testRestrictedProfilesAreAddedToVpn() {
setMockedUsers(primaryUser, secondaryUser, restrictedProfileA, restrictedProfileB); setMockedUsers(primaryUser, secondaryUser, restrictedProfileA, restrictedProfileB);
final Vpn vpn = spyVpn(primaryUser.id); final Vpn vpn = createVpn(primaryUser.id);
final Set<UidRange> ranges = vpn.createUserAndRestrictedProfilesRanges(primaryUser.id, final Set<UidRange> ranges = vpn.createUserAndRestrictedProfilesRanges(primaryUser.id,
null, null); null, null);
@@ -125,7 +135,7 @@ public class VpnTest extends AndroidTestCase {
public void testManagedProfilesAreNotAddedToVpn() { public void testManagedProfilesAreNotAddedToVpn() {
setMockedUsers(primaryUser, managedProfileA); setMockedUsers(primaryUser, managedProfileA);
final Vpn vpn = spyVpn(primaryUser.id); final Vpn vpn = createVpn(primaryUser.id);
final Set<UidRange> ranges = vpn.createUserAndRestrictedProfilesRanges(primaryUser.id, final Set<UidRange> ranges = vpn.createUserAndRestrictedProfilesRanges(primaryUser.id,
null, null); null, null);
@@ -138,7 +148,7 @@ public class VpnTest extends AndroidTestCase {
public void testAddUserToVpnOnlyAddsOneUser() { public void testAddUserToVpnOnlyAddsOneUser() {
setMockedUsers(primaryUser, restrictedProfileA, managedProfileA); setMockedUsers(primaryUser, restrictedProfileA, managedProfileA);
final Vpn vpn = spyVpn(primaryUser.id); final Vpn vpn = createVpn(primaryUser.id);
final Set<UidRange> ranges = new ArraySet<>(); final Set<UidRange> ranges = new ArraySet<>();
vpn.addUserToRanges(ranges, primaryUser.id, null, null); vpn.addUserToRanges(ranges, primaryUser.id, null, null);
@@ -149,7 +159,7 @@ public class VpnTest extends AndroidTestCase {
@SmallTest @SmallTest
public void testUidWhiteAndBlacklist() throws Exception { public void testUidWhiteAndBlacklist() throws Exception {
final Vpn vpn = spyVpn(primaryUser.id); final Vpn vpn = createVpn(primaryUser.id);
final UidRange user = UidRange.createForUser(primaryUser.id); final UidRange user = UidRange.createForUser(primaryUser.id);
final String[] packages = {PKGS[0], PKGS[1], PKGS[2]}; final String[] packages = {PKGS[0], PKGS[1], PKGS[2]};
@@ -174,7 +184,7 @@ public class VpnTest extends AndroidTestCase {
@SmallTest @SmallTest
public void testLockdownChangingPackage() throws Exception { public void testLockdownChangingPackage() throws Exception {
final Vpn vpn = spyVpn(primaryUser.id); final Vpn vpn = createVpn(primaryUser.id);
final UidRange user = UidRange.createForUser(primaryUser.id); final UidRange user = UidRange.createForUser(primaryUser.id);
// Default state. // Default state.
@@ -209,7 +219,7 @@ public class VpnTest extends AndroidTestCase {
@SmallTest @SmallTest
public void testLockdownAddingAProfile() throws Exception { public void testLockdownAddingAProfile() throws Exception {
final Vpn vpn = spyVpn(primaryUser.id); final Vpn vpn = createVpn(primaryUser.id);
setMockedUsers(primaryUser); setMockedUsers(primaryUser);
// Make a copy of the restricted profile, as we're going to mark it deleted halfway through. // Make a copy of the restricted profile, as we're going to mark it deleted halfway through.
@@ -249,40 +259,41 @@ public class VpnTest extends AndroidTestCase {
@SmallTest @SmallTest
public void testNotificationShownForAlwaysOnApp() { public void testNotificationShownForAlwaysOnApp() {
final Vpn vpn = spyVpn(primaryUser.id); final UserHandle userHandle = UserHandle.of(primaryUser.id);
final InOrder order = inOrder(vpn); final Vpn vpn = createVpn(primaryUser.id);
setMockedUsers(primaryUser); setMockedUsers(primaryUser);
final InOrder order = inOrder(mNotificationManager);
// Don't show a notification for regular disconnected states. // Don't show a notification for regular disconnected states.
vpn.updateState(DetailedState.DISCONNECTED, TAG); vpn.updateState(DetailedState.DISCONNECTED, TAG);
order.verify(vpn).updateAlwaysOnNotificationInternal(false); order.verify(mNotificationManager, atLeastOnce())
.cancelAsUser(anyString(), anyInt(), eq(userHandle));
// Start showing a notification for disconnected once always-on. // Start showing a notification for disconnected once always-on.
vpn.setAlwaysOnPackage(PKGS[0], false); vpn.setAlwaysOnPackage(PKGS[0], false);
order.verify(vpn).updateAlwaysOnNotificationInternal(true); order.verify(mNotificationManager)
.notifyAsUser(anyString(), anyInt(), any(), eq(userHandle));
// Stop showing the notification once connected. // Stop showing the notification once connected.
vpn.updateState(DetailedState.CONNECTED, TAG); vpn.updateState(DetailedState.CONNECTED, TAG);
order.verify(vpn).updateAlwaysOnNotificationInternal(false); order.verify(mNotificationManager).cancelAsUser(anyString(), anyInt(), eq(userHandle));
// Show the notification if we disconnect again. // Show the notification if we disconnect again.
vpn.updateState(DetailedState.DISCONNECTED, TAG); vpn.updateState(DetailedState.DISCONNECTED, TAG);
order.verify(vpn).updateAlwaysOnNotificationInternal(true); order.verify(mNotificationManager)
.notifyAsUser(anyString(), anyInt(), any(), eq(userHandle));
// Notification should be cleared after unsetting always-on package. // Notification should be cleared after unsetting always-on package.
vpn.setAlwaysOnPackage(null, false); vpn.setAlwaysOnPackage(null, false);
order.verify(vpn).updateAlwaysOnNotificationInternal(false); order.verify(mNotificationManager).cancelAsUser(anyString(), anyInt(), eq(userHandle));
} }
/** /**
* Mock some methods of vpn object. * Mock some methods of vpn object.
*/ */
private Vpn spyVpn(@UserIdInt int userId) { private Vpn createVpn(@UserIdInt int userId) {
final Vpn vpn = spy(new Vpn(Looper.myLooper(), mContext, mNetService, userId)); return new Vpn(Looper.myLooper(), mContext, mNetService, userId, mSystemServices);
// Block calls to the NotificationManager or PendingIntent#getActivity.
doNothing().when(vpn).updateAlwaysOnNotificationInternal(anyBoolean());
return vpn;
} }
private static void assertBlocked(Vpn vpn, int... uids) { private static void assertBlocked(Vpn vpn, int... uids) {