1 /* 2 * Copyright (C) 2014 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 package com.android.systemui.statusbar.policy; 17 18 import android.app.ActivityManager; 19 import android.app.admin.DevicePolicyManager; 20 import android.content.Context; 21 import android.content.pm.PackageManager.NameNotFoundException; 22 import android.net.ConnectivityManager; 23 import android.net.ConnectivityManager.NetworkCallback; 24 import android.net.IConnectivityManager; 25 import android.net.Network; 26 import android.net.NetworkCapabilities; 27 import android.net.NetworkRequest; 28 import android.os.RemoteException; 29 import android.os.ServiceManager; 30 import android.text.TextUtils; 31 import android.util.Log; 32 33 import com.android.internal.net.VpnConfig; 34 35 import java.io.FileDescriptor; 36 import java.io.PrintWriter; 37 import java.util.ArrayList; 38 39 public class SecurityControllerImpl implements SecurityController { 40 41 private static final String TAG = "SecurityController"; 42 private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG); 43 44 private static final NetworkRequest REQUEST = new NetworkRequest.Builder() 45 .removeCapability(NetworkCapabilities.NET_CAPABILITY_NOT_VPN) 46 .removeCapability(NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED) 47 .removeCapability(NetworkCapabilities.NET_CAPABILITY_TRUSTED) 48 .build(); 49 private static final int NO_NETWORK = -1; 50 51 private final Context mContext; 52 private final ConnectivityManager mConnectivityManager; 53 private final IConnectivityManager mConnectivityService = IConnectivityManager.Stub.asInterface( 54 ServiceManager.getService(Context.CONNECTIVITY_SERVICE)); 55 private final DevicePolicyManager mDevicePolicyManager; 56 private final ArrayList<SecurityControllerCallback> mCallbacks 57 = new ArrayList<SecurityControllerCallback>(); 58 59 private VpnConfig mVpnConfig; 60 private String mVpnName; 61 private int mCurrentVpnNetworkId = NO_NETWORK; 62 private int mCurrentUserId; 63 64 public SecurityControllerImpl(Context context) { 65 mContext = context; 66 mDevicePolicyManager = (DevicePolicyManager) 67 context.getSystemService(Context.DEVICE_POLICY_SERVICE); 68 mConnectivityManager = (ConnectivityManager) 69 context.getSystemService(Context.CONNECTIVITY_SERVICE); 70 71 // TODO: re-register network callback on user change. 72 mConnectivityManager.registerNetworkCallback(REQUEST, mNetworkCallback); 73 mCurrentUserId = ActivityManager.getCurrentUser(); 74 } 75 76 public void dump(FileDescriptor fd, PrintWriter pw, String[] args) { 77 pw.println("SecurityController state:"); 78 pw.print(" mCurrentVpnNetworkId="); pw.println(mCurrentVpnNetworkId); 79 pw.print(" mVpnConfig="); pw.println(mVpnConfig); 80 pw.print(" mVpnName="); pw.println(mVpnName); 81 } 82 83 @Override 84 public boolean hasDeviceOwner() { 85 return !TextUtils.isEmpty(mDevicePolicyManager.getDeviceOwner()); 86 } 87 88 @Override 89 public boolean hasProfileOwner() { 90 return !TextUtils.isEmpty(mDevicePolicyManager.getProfileOwnerNameAsUser(mCurrentUserId)); 91 } 92 93 @Override 94 public String getDeviceOwnerName() { 95 return mDevicePolicyManager.getDeviceOwnerName(); 96 } 97 98 @Override 99 public String getProfileOwnerName() { 100 return mDevicePolicyManager.getProfileOwnerNameAsUser(mCurrentUserId); 101 } 102 103 104 @Override 105 public boolean isVpnEnabled() { 106 return mCurrentVpnNetworkId != NO_NETWORK; 107 } 108 109 @Override 110 public boolean isLegacyVpn() { 111 return mVpnConfig.legacy; 112 } 113 114 @Override 115 public String getVpnApp() { 116 return mVpnName; 117 } 118 119 @Override 120 public String getLegacyVpnName() { 121 return mVpnConfig.session; 122 } 123 124 @Override 125 public void disconnectFromVpn() { 126 try { 127 if (isLegacyVpn()) { 128 mConnectivityService.prepareVpn(VpnConfig.LEGACY_VPN, VpnConfig.LEGACY_VPN); 129 } else { 130 // Prevent this app from initiating VPN connections in the future without user 131 // intervention. 132 mConnectivityService.setVpnPackageAuthorization(false); 133 134 mConnectivityService.prepareVpn(mVpnConfig.user, VpnConfig.LEGACY_VPN); 135 } 136 } catch (Exception e) { 137 Log.e(TAG, "Unable to disconnect from VPN", e); 138 } 139 } 140 141 @Override 142 public void removeCallback(SecurityControllerCallback callback) { 143 if (callback == null) return; 144 if (DEBUG) Log.d(TAG, "removeCallback " + callback); 145 mCallbacks.remove(callback); 146 } 147 148 @Override 149 public void addCallback(SecurityControllerCallback callback) { 150 if (callback == null || mCallbacks.contains(callback)) return; 151 if (DEBUG) Log.d(TAG, "addCallback " + callback); 152 mCallbacks.add(callback); 153 } 154 155 @Override 156 public void onUserSwitched(int newUserId) { 157 mCurrentUserId = newUserId; 158 fireCallbacks(); 159 } 160 161 private void setCurrentNetid(int netId) { 162 if (netId != mCurrentVpnNetworkId) { 163 mCurrentVpnNetworkId = netId; 164 updateState(); 165 fireCallbacks(); 166 } 167 } 168 169 private void fireCallbacks() { 170 for (SecurityControllerCallback callback : mCallbacks) { 171 callback.onStateChanged(); 172 } 173 } 174 175 private void updateState() { 176 try { 177 mVpnConfig = mConnectivityService.getVpnConfig(); 178 179 if (mVpnConfig != null && !mVpnConfig.legacy) { 180 mVpnName = VpnConfig.getVpnLabel(mContext, mVpnConfig.user).toString(); 181 } 182 } catch (RemoteException | NameNotFoundException e) { 183 Log.w(TAG, "Unable to get current VPN", e); 184 } 185 } 186 187 private final NetworkCallback mNetworkCallback = new NetworkCallback() { 188 @Override 189 public void onAvailable(Network network) { 190 NetworkCapabilities networkCapabilities = 191 mConnectivityManager.getNetworkCapabilities(network); 192 if (DEBUG) Log.d(TAG, "onAvailable " + network.netId + " : " + networkCapabilities); 193 if (networkCapabilities.hasTransport(NetworkCapabilities.TRANSPORT_VPN)) { 194 setCurrentNetid(network.netId); 195 } 196 }; 197 198 // TODO Find another way to receive VPN lost. This may be delayed depending on 199 // how long the VPN connection is held on to. 200 @Override 201 public void onLost(Network network) { 202 if (DEBUG) Log.d(TAG, "onLost " + network.netId); 203 if (mCurrentVpnNetworkId == network.netId) { 204 setCurrentNetid(NO_NETWORK); 205 } 206 }; 207 }; 208 209 } 210