| /* |
| * Copyright (C) 2014 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.systemui.statusbar.policy; |
| |
| import android.app.ActivityManager; |
| import android.app.admin.DevicePolicyManager; |
| import android.content.Context; |
| import android.content.pm.PackageManager.NameNotFoundException; |
| import android.net.ConnectivityManager; |
| import android.net.ConnectivityManager.NetworkCallback; |
| import android.net.IConnectivityManager; |
| import android.net.Network; |
| import android.net.NetworkCapabilities; |
| import android.net.NetworkRequest; |
| import android.os.RemoteException; |
| import android.os.ServiceManager; |
| import android.text.TextUtils; |
| import android.util.Log; |
| |
| import com.android.internal.net.VpnConfig; |
| |
| import java.io.FileDescriptor; |
| import java.io.PrintWriter; |
| import java.util.ArrayList; |
| |
| public class SecurityControllerImpl implements SecurityController { |
| |
| private static final String TAG = "SecurityController"; |
| private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG); |
| |
| private static final NetworkRequest REQUEST = new NetworkRequest.Builder() |
| .removeCapability(NetworkCapabilities.NET_CAPABILITY_NOT_VPN) |
| .removeCapability(NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED) |
| .removeCapability(NetworkCapabilities.NET_CAPABILITY_TRUSTED) |
| .build(); |
| private static final int NO_NETWORK = -1; |
| |
| private final Context mContext; |
| private final ConnectivityManager mConnectivityManager; |
| private final IConnectivityManager mConnectivityService = IConnectivityManager.Stub.asInterface( |
| ServiceManager.getService(Context.CONNECTIVITY_SERVICE)); |
| private final DevicePolicyManager mDevicePolicyManager; |
| private final ArrayList<SecurityControllerCallback> mCallbacks |
| = new ArrayList<SecurityControllerCallback>(); |
| |
| private VpnConfig mVpnConfig; |
| private String mVpnName; |
| private int mCurrentVpnNetworkId = NO_NETWORK; |
| private int mCurrentUserId; |
| |
| public SecurityControllerImpl(Context context) { |
| mContext = context; |
| mDevicePolicyManager = (DevicePolicyManager) |
| context.getSystemService(Context.DEVICE_POLICY_SERVICE); |
| mConnectivityManager = (ConnectivityManager) |
| context.getSystemService(Context.CONNECTIVITY_SERVICE); |
| |
| // TODO: re-register network callback on user change. |
| mConnectivityManager.registerNetworkCallback(REQUEST, mNetworkCallback); |
| mCurrentUserId = ActivityManager.getCurrentUser(); |
| } |
| |
| public void dump(FileDescriptor fd, PrintWriter pw, String[] args) { |
| pw.println("SecurityController state:"); |
| pw.print(" mCurrentVpnNetworkId="); pw.println(mCurrentVpnNetworkId); |
| pw.print(" mVpnConfig="); pw.println(mVpnConfig); |
| pw.print(" mVpnName="); pw.println(mVpnName); |
| } |
| |
| @Override |
| public boolean hasDeviceOwner() { |
| return !TextUtils.isEmpty(mDevicePolicyManager.getDeviceOwner()); |
| } |
| |
| @Override |
| public boolean hasProfileOwner() { |
| return !TextUtils.isEmpty(mDevicePolicyManager.getProfileOwnerNameAsUser(mCurrentUserId)); |
| } |
| |
| @Override |
| public String getDeviceOwnerName() { |
| return mDevicePolicyManager.getDeviceOwnerName(); |
| } |
| |
| @Override |
| public String getProfileOwnerName() { |
| return mDevicePolicyManager.getProfileOwnerNameAsUser(mCurrentUserId); |
| } |
| |
| |
| @Override |
| public boolean isVpnEnabled() { |
| return mCurrentVpnNetworkId != NO_NETWORK; |
| } |
| |
| @Override |
| public boolean isLegacyVpn() { |
| return mVpnConfig.legacy; |
| } |
| |
| @Override |
| public String getVpnApp() { |
| return mVpnName; |
| } |
| |
| @Override |
| public String getLegacyVpnName() { |
| return mVpnConfig.session; |
| } |
| |
| @Override |
| public void disconnectFromVpn() { |
| try { |
| if (isLegacyVpn()) { |
| mConnectivityService.prepareVpn(VpnConfig.LEGACY_VPN, VpnConfig.LEGACY_VPN); |
| } else { |
| // Prevent this app from initiating VPN connections in the future without user |
| // intervention. |
| mConnectivityService.setVpnPackageAuthorization(false); |
| |
| mConnectivityService.prepareVpn(mVpnConfig.user, VpnConfig.LEGACY_VPN); |
| } |
| } catch (Exception e) { |
| Log.e(TAG, "Unable to disconnect from VPN", e); |
| } |
| } |
| |
| @Override |
| public void removeCallback(SecurityControllerCallback callback) { |
| if (callback == null) return; |
| if (DEBUG) Log.d(TAG, "removeCallback " + callback); |
| mCallbacks.remove(callback); |
| } |
| |
| @Override |
| public void addCallback(SecurityControllerCallback callback) { |
| if (callback == null || mCallbacks.contains(callback)) return; |
| if (DEBUG) Log.d(TAG, "addCallback " + callback); |
| mCallbacks.add(callback); |
| } |
| |
| @Override |
| public void onUserSwitched(int newUserId) { |
| mCurrentUserId = newUserId; |
| fireCallbacks(); |
| } |
| |
| private void setCurrentNetid(int netId) { |
| if (netId != mCurrentVpnNetworkId) { |
| mCurrentVpnNetworkId = netId; |
| updateState(); |
| fireCallbacks(); |
| } |
| } |
| |
| private void fireCallbacks() { |
| for (SecurityControllerCallback callback : mCallbacks) { |
| callback.onStateChanged(); |
| } |
| } |
| |
| private void updateState() { |
| try { |
| mVpnConfig = mConnectivityService.getVpnConfig(); |
| |
| if (mVpnConfig != null && !mVpnConfig.legacy) { |
| mVpnName = VpnConfig.getVpnLabel(mContext, mVpnConfig.user).toString(); |
| } |
| } catch (RemoteException | NameNotFoundException e) { |
| Log.w(TAG, "Unable to get current VPN", e); |
| } |
| } |
| |
| private final NetworkCallback mNetworkCallback = new NetworkCallback() { |
| @Override |
| public void onAvailable(Network network) { |
| NetworkCapabilities networkCapabilities = |
| mConnectivityManager.getNetworkCapabilities(network); |
| if (DEBUG) Log.d(TAG, "onAvailable " + network.netId + " : " + networkCapabilities); |
| if (networkCapabilities.hasTransport(NetworkCapabilities.TRANSPORT_VPN)) { |
| setCurrentNetid(network.netId); |
| } |
| }; |
| |
| // TODO Find another way to receive VPN lost. This may be delayed depending on |
| // how long the VPN connection is held on to. |
| @Override |
| public void onLost(Network network) { |
| if (DEBUG) Log.d(TAG, "onLost " + network.netId); |
| if (mCurrentVpnNetworkId == network.netId) { |
| setCurrentNetid(NO_NETWORK); |
| } |
| }; |
| }; |
| |
| } |