blob: 3295bf5f03dde267217b48217fb7e035c0a73025 [file] [log] [blame]
/*
* Copyright (C) 2016 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.server.connectivity;
import static android.content.pm.UserInfo.FLAG_ADMIN;
import static android.content.pm.UserInfo.FLAG_MANAGED_PROFILE;
import static android.content.pm.UserInfo.FLAG_PRIMARY;
import static android.content.pm.UserInfo.FLAG_RESTRICTED;
import static org.mockito.Mockito.*;
import android.annotation.UserIdInt;
import android.content.Context;
import android.content.pm.PackageManager;
import android.content.pm.UserInfo;
import android.net.UidRange;
import android.os.INetworkManagementService;
import android.os.Looper;
import android.os.UserHandle;
import android.os.UserManager;
import android.test.AndroidTestCase;
import android.test.suitebuilder.annotation.SmallTest;
import android.util.ArrayMap;
import android.util.ArraySet;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Map;
import java.util.Set;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
/**
* Tests for {@link Vpn}.
*
* Build, install and run with:
* runtest --path src/com/android/server/connectivity/VpnTest.java
*/
public class VpnTest extends AndroidTestCase {
private static final String TAG = "VpnTest";
// Mock users
static final UserInfo primaryUser = new UserInfo(27, "Primary", FLAG_ADMIN | FLAG_PRIMARY);
static final UserInfo secondaryUser = new UserInfo(15, "Secondary", FLAG_ADMIN);
static final UserInfo restrictedProfileA = new UserInfo(40, "RestrictedA", FLAG_RESTRICTED);
static final UserInfo restrictedProfileB = new UserInfo(42, "RestrictedB", FLAG_RESTRICTED);
static final UserInfo managedProfileA = new UserInfo(45, "ManagedA", FLAG_MANAGED_PROFILE);
static {
restrictedProfileA.restrictedProfileParentId = primaryUser.id;
restrictedProfileB.restrictedProfileParentId = secondaryUser.id;
managedProfileA.profileGroupId = primaryUser.id;
}
@Mock private Context mContext;
@Mock private UserManager mUserManager;
@Mock private PackageManager mPackageManager;
@Mock private INetworkManagementService mNetService;
@Override
public void setUp() throws Exception {
MockitoAnnotations.initMocks(this);
when(mContext.getPackageManager()).thenReturn(mPackageManager);
when(mContext.getSystemService(eq(Context.USER_SERVICE))).thenReturn(mUserManager);
doNothing().when(mNetService).registerObserver(any());
}
@SmallTest
public void testRestrictedProfilesAreAddedToVpn() {
setMockedUsers(primaryUser, secondaryUser, restrictedProfileA, restrictedProfileB);
final Vpn vpn = createVpn(primaryUser.id);
final Set<UidRange> ranges = vpn.createUserAndRestrictedProfilesRanges(primaryUser.id,
null, null);
assertEquals(new ArraySet<>(Arrays.asList(new UidRange[] {
UidRange.createForUser(primaryUser.id),
UidRange.createForUser(restrictedProfileA.id)
})), ranges);
}
@SmallTest
public void testManagedProfilesAreNotAddedToVpn() {
setMockedUsers(primaryUser, managedProfileA);
final Vpn vpn = createVpn(primaryUser.id);
final Set<UidRange> ranges = vpn.createUserAndRestrictedProfilesRanges(primaryUser.id,
null, null);
assertEquals(new ArraySet<>(Arrays.asList(new UidRange[] {
UidRange.createForUser(primaryUser.id)
})), ranges);
}
@SmallTest
public void testAddUserToVpnOnlyAddsOneUser() {
setMockedUsers(primaryUser, restrictedProfileA, managedProfileA);
final Vpn vpn = createVpn(primaryUser.id);
final Set<UidRange> ranges = new ArraySet<>();
vpn.addUserToRanges(ranges, primaryUser.id, null, null);
assertEquals(new ArraySet<>(Arrays.asList(new UidRange[] {
UidRange.createForUser(primaryUser.id)
})), ranges);
}
@SmallTest
public void testUidWhiteAndBlacklist() throws Exception {
final Map<String, Integer> packages = new ArrayMap<>();
packages.put("com.example", 66);
packages.put("org.example", 77);
packages.put("net.example", 78);
setMockedPackages(packages);
final Vpn vpn = createVpn(primaryUser.id);
final UidRange user = UidRange.createForUser(primaryUser.id);
// Whitelist
final Set<UidRange> allow = vpn.createUserAndRestrictedProfilesRanges(primaryUser.id,
new ArrayList<String>(packages.keySet()), null);
assertEquals(new ArraySet<>(Arrays.asList(new UidRange[] {
new UidRange(user.start + 66, user.start + 66),
new UidRange(user.start + 77, user.start + 78)
})), allow);
// Blacklist
final Set<UidRange> disallow = vpn.createUserAndRestrictedProfilesRanges(primaryUser.id,
null, new ArrayList<String>(packages.keySet()));
assertEquals(new ArraySet<>(Arrays.asList(new UidRange[] {
new UidRange(user.start, user.start + 65),
new UidRange(user.start + 67, user.start + 76),
new UidRange(user.start + 79, user.stop)
})), disallow);
}
/**
* @return A subclass of {@link Vpn} which is reliably:
* <ul>
* <li>Associated with a specific user ID</li>
* <li>Not in always-on mode</li>
* </ul>
*/
private Vpn createVpn(@UserIdInt int userId) {
return new Vpn(Looper.myLooper(), mContext, mNetService, userId);
}
/**
* Populate {@link #mUserManager} with a list of fake users.
*/
private void setMockedUsers(UserInfo... users) {
final Map<Integer, UserInfo> userMap = new ArrayMap<>();
for (UserInfo user : users) {
userMap.put(user.id, user);
}
doAnswer(invocation -> {
return new ArrayList(userMap.values());
}).when(mUserManager).getUsers();
doAnswer(invocation -> {
final int id = (int) invocation.getArguments()[0];
return userMap.get(id);
}).when(mUserManager).getUserInfo(anyInt());
doAnswer(invocation -> {
final int id = (int) invocation.getArguments()[0];
return (userMap.get(id).flags & UserInfo.FLAG_ADMIN) != 0;
}).when(mUserManager).canHaveRestrictedProfile(anyInt());
}
/**
* Populate {@link #mPackageManager} with a fake packageName-to-UID mapping.
*/
private void setMockedPackages(final Map<String, Integer> packages) {
try {
doAnswer(invocation -> {
final String appName = (String) invocation.getArguments()[0];
final int userId = (int) invocation.getArguments()[1];
return UserHandle.getUid(userId, packages.get(appName));
}).when(mPackageManager).getPackageUidAsUser(anyString(), anyInt());
} catch (Exception e) {
}
}
}