Fixed VPN support for restricted profiles in split system user model
In a new split system user model, owner of a restricted profile is not limited
to just user0. restrictedProfileParentId field should be used to get an owner.
Bug: 22950929
Change-Id: I928319a9450e543972237a42267eb2404e117c83
diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java
index 6190a5a..a7e6f11 100644
--- a/services/core/java/com/android/server/ConnectivityService.java
+++ b/services/core/java/com/android/server/ConnectivityService.java
@@ -754,6 +754,8 @@
IntentFilter intentFilter = new IntentFilter();
intentFilter.addAction(Intent.ACTION_USER_STARTING);
intentFilter.addAction(Intent.ACTION_USER_STOPPING);
+ intentFilter.addAction(Intent.ACTION_USER_ADDED);
+ intentFilter.addAction(Intent.ACTION_USER_REMOVED);
mContext.registerReceiverAsUser(
mUserIntentReceiver, UserHandle.ALL, intentFilter, null, null);
@@ -3525,6 +3527,26 @@
}
}
+ private void onUserAdded(int userId) {
+ synchronized(mVpns) {
+ final int vpnsSize = mVpns.size();
+ for (int i = 0; i < vpnsSize; i++) {
+ Vpn vpn = mVpns.valueAt(i);
+ vpn.onUserAdded(userId);
+ }
+ }
+ }
+
+ private void onUserRemoved(int userId) {
+ synchronized(mVpns) {
+ final int vpnsSize = mVpns.size();
+ for (int i = 0; i < vpnsSize; i++) {
+ Vpn vpn = mVpns.valueAt(i);
+ vpn.onUserRemoved(userId);
+ }
+ }
+ }
+
private BroadcastReceiver mUserIntentReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
@@ -3536,6 +3558,10 @@
onUserStart(userId);
} else if (Intent.ACTION_USER_STOPPING.equals(action)) {
onUserStop(userId);
+ } else if (Intent.ACTION_USER_ADDED.equals(action)) {
+ onUserAdded(userId);
+ } else if (Intent.ACTION_USER_REMOVED.equals(action)) {
+ onUserRemoved(userId);
}
}
};
diff --git a/services/core/java/com/android/server/connectivity/Vpn.java b/services/core/java/com/android/server/connectivity/Vpn.java
index 3df3cd0..2bea278 100644
--- a/services/core/java/com/android/server/connectivity/Vpn.java
+++ b/services/core/java/com/android/server/connectivity/Vpn.java
@@ -20,9 +20,6 @@
import static android.net.ConnectivityManager.NETID_UNSET;
import static android.net.RouteInfo.RTN_THROW;
import static android.net.RouteInfo.RTN_UNREACHABLE;
-import static android.os.UserHandle.PER_USER_RANGE;
-import static android.system.OsConstants.AF_INET;
-import static android.system.OsConstants.AF_INET6;
import android.Manifest;
import android.app.AppGlobals;
@@ -34,13 +31,11 @@
import android.content.Intent;
import android.content.IntentFilter;
import android.content.ServiceConnection;
-import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
import android.content.pm.PackageManager.NameNotFoundException;
import android.content.pm.ResolveInfo;
import android.content.pm.UserInfo;
import android.net.ConnectivityManager;
-import android.net.IConnectivityManager;
import android.net.INetworkManagementEventObserver;
import android.net.IpPrefix;
import android.net.LinkAddress;
@@ -126,7 +121,6 @@
/* list of users using this VPN. */
@GuardedBy("this")
private List<UidRange> mVpnUsers = null;
- private BroadcastReceiver mUserIntentReceiver = null;
// Handle of user initiating VPN.
private final int mUserHandle;
@@ -146,31 +140,6 @@
} catch (RemoteException e) {
Log.wtf(TAG, "Problem registering observer", e);
}
- // TODO: http://b/22950929
- if (userHandle == UserHandle.USER_SYSTEM) {
- // Owner's VPN also needs to handle restricted users
- mUserIntentReceiver = new BroadcastReceiver() {
- @Override
- public void onReceive(Context context, Intent intent) {
- final String action = intent.getAction();
- final int userHandle = intent.getIntExtra(Intent.EXTRA_USER_HANDLE,
- UserHandle.USER_NULL);
- if (userHandle == UserHandle.USER_NULL) return;
-
- if (Intent.ACTION_USER_ADDED.equals(action)) {
- onUserAdded(userHandle);
- } else if (Intent.ACTION_USER_REMOVED.equals(action)) {
- onUserRemoved(userHandle);
- }
- }
- };
-
- IntentFilter intentFilter = new IntentFilter();
- intentFilter.addAction(Intent.ACTION_USER_ADDED);
- intentFilter.addAction(Intent.ACTION_USER_REMOVED);
- mContext.registerReceiverAsUser(
- mUserIntentReceiver, UserHandle.ALL, intentFilter, null, null);
- }
mNetworkInfo = new NetworkInfo(ConnectivityManager.TYPE_VPN, 0, NETWORKTYPE, "");
// TODO: Copy metered attribute and bandwidths from physical transport, b/16207332
@@ -439,8 +408,8 @@
}
addVpnUserLocked(mUserHandle);
- // If we are owner assign all Restricted Users to this VPN
- if (mUserHandle == UserHandle.USER_OWNER) {
+ // If the user can have restricted profiles, assign all its restricted profiles to this VPN
+ if (canHaveRestrictedProfile(mUserHandle)) {
token = Binder.clearCallingIdentity();
List<UserInfo> users;
try {
@@ -449,7 +418,7 @@
Binder.restoreCallingIdentity(token);
}
for (UserInfo user : users) {
- if (user.isRestricted()) {
+ if (user.isRestricted() && (user.restrictedProfileParentId == mUserHandle)) {
addVpnUserLocked(user.id);
}
}
@@ -457,6 +426,15 @@
mNetworkAgent.addUidRanges(mVpnUsers.toArray(new UidRange[mVpnUsers.size()]));
}
+ private boolean canHaveRestrictedProfile(int userId) {
+ long token = Binder.clearCallingIdentity();
+ try {
+ return UserManager.get(mContext).canHaveRestrictedProfile(userId);
+ } finally {
+ Binder.restoreCallingIdentity(token);
+ }
+ }
+
private void agentDisconnect(NetworkInfo networkInfo, NetworkAgent networkAgent) {
networkInfo.setIsAvailable(false);
networkInfo.setDetailedState(DetailedState.DISCONNECTED, null, null);
@@ -681,12 +659,11 @@
mStatusIntent = null;
}
- private void onUserAdded(int userHandle) {
- // If the user is restricted tie them to the owner's VPN
- synchronized(Vpn.this) {
- UserManager mgr = UserManager.get(mContext);
- UserInfo user = mgr.getUserInfo(userHandle);
- if (user.isRestricted()) {
+ public void onUserAdded(int userHandle) {
+ // If the user is restricted tie them to the parent user's VPN
+ UserInfo user = UserManager.get(mContext).getUserInfo(userHandle);
+ if (user.isRestricted() && user.restrictedProfileParentId == mUserHandle) {
+ synchronized(Vpn.this) {
try {
addVpnUserLocked(userHandle);
if (mNetworkAgent != null) {
@@ -700,12 +677,11 @@
}
}
- private void onUserRemoved(int userHandle) {
+ public void onUserRemoved(int userHandle) {
// clean up if restricted
- synchronized(Vpn.this) {
- UserManager mgr = UserManager.get(mContext);
- UserInfo user = mgr.getUserInfo(userHandle);
- if (user.isRestricted()) {
+ UserInfo user = UserManager.get(mContext).getUserInfo(userHandle);
+ if (user.isRestricted() && user.restrictedProfileParentId == mUserHandle) {
+ synchronized(Vpn.this) {
try {
removeVpnUserLocked(userHandle);
} catch (Exception e) {
diff --git a/services/core/java/com/android/server/pm/UserManagerService.java b/services/core/java/com/android/server/pm/UserManagerService.java
index 0577d59..de106a1 100644
--- a/services/core/java/com/android/server/pm/UserManagerService.java
+++ b/services/core/java/com/android/server/pm/UserManagerService.java
@@ -131,7 +131,7 @@
private static final int MIN_USER_ID = 10;
- private static final int USER_VERSION = 5;
+ private static final int USER_VERSION = 6;
private static final long EPOCH_PLUS_30_YEARS = 30L * 365 * 24 * 60 * 60 * 1000L; // ms
@@ -408,6 +408,24 @@
}
}
+ @Override
+ public boolean canHaveRestrictedProfile(int userId) {
+ checkManageUsersPermission("canHaveRestrictedProfile");
+ synchronized (mPackagesLock) {
+ final UserInfo userInfo = getUserInfoLocked(userId);
+ if (userInfo == null || !userInfo.canHaveProfile()) {
+ return false;
+ }
+ if (!userInfo.isAdmin()) {
+ return false;
+ }
+ }
+ DevicePolicyManager dpm = (DevicePolicyManager) mContext.getSystemService(
+ Context.DEVICE_POLICY_SERVICE);
+ // restricted profile can be created if there is no DO set and the admin user has no PO
+ return dpm.getDeviceOwner() == null && dpm.getProfileOwnerAsUser(userId) == null;
+ }
+
/*
* Should be locked on mUsers before calling this.
*/
@@ -848,6 +866,20 @@
userVersion = 5;
}
+ if (userVersion < 6) {
+ final boolean splitSystemUser = UserManager.isSplitSystemUser();
+ for (int i = 0; i < mUsers.size(); i++) {
+ UserInfo user = mUsers.valueAt(i);
+ // In non-split mode, only user 0 can have restricted profiles
+ if (!splitSystemUser && user.isRestricted()
+ && (user.restrictedProfileParentId == UserInfo.NO_PROFILE_GROUP_ID)) {
+ user.restrictedProfileParentId = UserHandle.USER_SYSTEM;
+ scheduleWriteUserLocked(user);
+ }
+ }
+ userVersion = 6;
+ }
+
if (userVersion < USER_VERSION) {
Slog.w(LOG_TAG, "User version " + mUserVersion + " didn't upgrade as expected to "
+ USER_VERSION);