Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 1c36315a authored by Fyodor Kupolov's avatar Fyodor Kupolov
Browse files

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
parent dfc9ce54
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -49,6 +49,7 @@ interface IUserManager {
    UserInfo getUserInfo(int userHandle);
    long getUserCreationTime(int userHandle);
    boolean isRestricted();
    boolean canHaveRestrictedProfile(int userId);
    int getUserSerialNumber(int userHandle);
    int getUserHandle(int userSerialNumber);
    Bundle getUserRestrictions(int userHandle);
+13 −0
Original line number Diff line number Diff line
@@ -631,6 +631,19 @@ public class UserManager {
        }
    }

    /**
     * Checks if specified user can have restricted profile.
     * @hide
     */
    public boolean canHaveRestrictedProfile(int userId) {
        try {
            return mService.canHaveRestrictedProfile(userId);
        } catch (RemoteException re) {
            Log.w(TAG, "Could not check if user can have restricted profile", re);
            return false;
        }
    }

    /**
     * Checks if the calling app is running as a guest user.
     * @return whether the caller is a guest user.
+3 −3
Original line number Diff line number Diff line
@@ -182,10 +182,10 @@ public class SecurityControllerImpl implements SecurityController {
    @Override
    public void onUserSwitched(int newUserId) {
        mCurrentUserId = newUserId;
        if (mUserManager.getUserInfo(newUserId).isRestricted()) {
        final UserInfo newUserInfo = mUserManager.getUserInfo(newUserId);
        if (newUserInfo.isRestricted()) {
            // VPN for a restricted profile is routed through its owner user
            // TODO: http://b/22950929
            mVpnUserId = UserHandle.USER_SYSTEM;
            mVpnUserId = newUserInfo.restrictedProfileParentId;
        } else {
            mVpnUserId = mCurrentUserId;
        }
+26 −0
Original line number Diff line number Diff line
@@ -754,6 +754,8 @@ public class ConnectivityService extends IConnectivityManager.Stub
        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 @@ public class ConnectivityService extends IConnectivityManager.Stub
        }
    }

    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 @@ public class ConnectivityService extends IConnectivityManager.Stub
                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);
            }
        }
    };
+21 −45
Original line number Diff line number Diff line
@@ -20,9 +20,6 @@ import static android.Manifest.permission.BIND_VPN_SERVICE;
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.Context;
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 @@ public class Vpn {
    /* 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 @@ public class Vpn {
        } 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 @@ public class Vpn {
        }

        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 @@ public class Vpn {
                Binder.restoreCallingIdentity(token);
            }
            for (UserInfo user : users) {
                if (user.isRestricted()) {
                if (user.isRestricted() && (user.restrictedProfileParentId == mUserHandle)) {
                    addVpnUserLocked(user.id);
                }
            }
@@ -457,6 +426,15 @@ public class Vpn {
        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 @@ public class Vpn {
        mStatusIntent = null;
    }

    private void onUserAdded(int userHandle) {
        // If the user is restricted tie them to the owner's VPN
    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) {
            UserManager mgr = UserManager.get(mContext);
            UserInfo user = mgr.getUserInfo(userHandle);
            if (user.isRestricted()) {
                try {
                    addVpnUserLocked(userHandle);
                    if (mNetworkAgent != null) {
@@ -700,12 +677,11 @@ public class Vpn {
        }
    }

    private void onUserRemoved(int userHandle) {
    public void onUserRemoved(int userHandle) {
        // clean up if restricted
        UserInfo user = UserManager.get(mContext).getUserInfo(userHandle);
        if (user.isRestricted() && user.restrictedProfileParentId == mUserHandle) {
            synchronized(Vpn.this) {
            UserManager mgr = UserManager.get(mContext);
            UserInfo user = mgr.getUserInfo(userHandle);
            if (user.isRestricted()) {
                try {
                    removeVpnUserLocked(userHandle);
                } catch (Exception e) {
Loading