2 * Copyright (C) 2014 The Android Open Source Project
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
16 package com
.android
.systemui
.statusbar
.policy
;
18 import android
.app
.ActivityManager
;
19 import android
.app
.admin
.DevicePolicyManager
;
20 import android
.content
.Context
;
21 import android
.content
.pm
.ApplicationInfo
;
22 import android
.content
.pm
.PackageManager
;
23 import android
.content
.pm
.PackageManager
.NameNotFoundException
;
24 import android
.content
.pm
.UserInfo
;
25 import android
.net
.ConnectivityManager
;
26 import android
.net
.ConnectivityManager
.NetworkCallback
;
27 import android
.net
.IConnectivityManager
;
28 import android
.net
.Network
;
29 import android
.net
.NetworkCapabilities
;
30 import android
.net
.NetworkRequest
;
31 import android
.os
.RemoteException
;
32 import android
.os
.ServiceManager
;
33 import android
.os
.UserHandle
;
34 import android
.os
.UserManager
;
35 import android
.util
.Log
;
36 import android
.util
.SparseArray
;
38 import com
.android
.internal
.annotations
.GuardedBy
;
39 import com
.android
.internal
.net
.LegacyVpnInfo
;
40 import com
.android
.internal
.net
.VpnConfig
;
41 import com
.android
.systemui
.R
;
43 import java
.io
.FileDescriptor
;
44 import java
.io
.PrintWriter
;
45 import java
.util
.ArrayList
;
47 public class SecurityControllerImpl
implements SecurityController
{
49 private static final String TAG
= "SecurityController";
50 private static final boolean DEBUG
= Log
.isLoggable(TAG
, Log
.DEBUG
);
52 private static final NetworkRequest REQUEST
= new NetworkRequest
.Builder()
53 .removeCapability(NetworkCapabilities
.NET_CAPABILITY_NOT_VPN
)
54 .removeCapability(NetworkCapabilities
.NET_CAPABILITY_NOT_RESTRICTED
)
55 .removeCapability(NetworkCapabilities
.NET_CAPABILITY_TRUSTED
)
57 private static final int NO_NETWORK
= -1;
59 private static final String VPN_BRANDED_META_DATA
= "com.android.systemui.IS_BRANDED";
61 private final Context mContext
;
62 private final ConnectivityManager mConnectivityManager
;
63 private final IConnectivityManager mConnectivityManagerService
;
64 private final DevicePolicyManager mDevicePolicyManager
;
65 private final PackageManager mPackageManager
;
66 private final UserManager mUserManager
;
68 @GuardedBy("mCallbacks")
69 private final ArrayList
<SecurityControllerCallback
> mCallbacks
= new ArrayList
<>();
71 private SparseArray
<VpnConfig
> mCurrentVpns
= new SparseArray
<>();
72 private int mCurrentUserId
;
73 private int mVpnUserId
;
75 public SecurityControllerImpl(Context context
) {
77 mDevicePolicyManager
= (DevicePolicyManager
)
78 context
.getSystemService(Context
.DEVICE_POLICY_SERVICE
);
79 mConnectivityManager
= (ConnectivityManager
)
80 context
.getSystemService(Context
.CONNECTIVITY_SERVICE
);
81 mConnectivityManagerService
= IConnectivityManager
.Stub
.asInterface(
82 ServiceManager
.getService(Context
.CONNECTIVITY_SERVICE
));
83 mPackageManager
= context
.getPackageManager();
84 mUserManager
= (UserManager
)
85 context
.getSystemService(Context
.USER_SERVICE
);
87 // TODO: re-register network callback on user change.
88 mConnectivityManager
.registerNetworkCallback(REQUEST
, mNetworkCallback
);
89 onUserSwitched(ActivityManager
.getCurrentUser());
92 public void dump(FileDescriptor fd
, PrintWriter pw
, String
[] args
) {
93 pw
.println("SecurityController state:");
94 pw
.print(" mCurrentVpns={");
95 for (int i
= 0 ; i
< mCurrentVpns
.size(); i
++) {
99 pw
.print(mCurrentVpns
.keyAt(i
));
101 pw
.print(mCurrentVpns
.valueAt(i
).user
);
107 public boolean isDeviceManaged() {
108 return mDevicePolicyManager
.isDeviceManaged();
112 public String
getDeviceOwnerName() {
113 return mDevicePolicyManager
.getDeviceOwnerNameOnAnyUser();
117 public boolean hasProfileOwner() {
118 return mDevicePolicyManager
.getProfileOwnerAsUser(mCurrentUserId
) != null;
122 public String
getProfileOwnerName() {
123 for (int profileId
: mUserManager
.getProfileIdsWithDisabled(mCurrentUserId
)) {
124 String name
= mDevicePolicyManager
.getProfileOwnerNameAsUser(profileId
);
133 public String
getPrimaryVpnName() {
134 VpnConfig cfg
= mCurrentVpns
.get(mVpnUserId
);
136 return getNameForVpnConfig(cfg
, new UserHandle(mVpnUserId
));
143 public String
getProfileVpnName() {
144 for (int profileId
: mUserManager
.getProfileIdsWithDisabled(mVpnUserId
)) {
145 if (profileId
== mVpnUserId
) {
148 VpnConfig cfg
= mCurrentVpns
.get(profileId
);
150 return getNameForVpnConfig(cfg
, UserHandle
.of(profileId
));
157 public boolean isVpnEnabled() {
158 for (int profileId
: mUserManager
.getProfileIdsWithDisabled(mVpnUserId
)) {
159 if (mCurrentVpns
.get(profileId
) != null) {
167 public boolean isVpnRestricted() {
168 UserHandle currentUser
= new UserHandle(mCurrentUserId
);
169 return mUserManager
.getUserInfo(mCurrentUserId
).isRestricted()
170 || mUserManager
.hasUserRestriction(UserManager
.DISALLOW_CONFIG_VPN
, currentUser
);
174 public boolean isVpnBranded() {
175 VpnConfig cfg
= mCurrentVpns
.get(mVpnUserId
);
180 String packageName
= getPackageNameForVpnConfig(cfg
);
181 if (packageName
== null) {
185 return isVpnPackageBranded(packageName
);
189 public void removeCallback(SecurityControllerCallback callback
) {
190 synchronized (mCallbacks
) {
191 if (callback
== null) return;
192 if (DEBUG
) Log
.d(TAG
, "removeCallback " + callback
);
193 mCallbacks
.remove(callback
);
198 public void addCallback(SecurityControllerCallback callback
) {
199 synchronized (mCallbacks
) {
200 if (callback
== null || mCallbacks
.contains(callback
)) return;
201 if (DEBUG
) Log
.d(TAG
, "addCallback " + callback
);
202 mCallbacks
.add(callback
);
207 public void onUserSwitched(int newUserId
) {
208 mCurrentUserId
= newUserId
;
209 final UserInfo newUserInfo
= mUserManager
.getUserInfo(newUserId
);
210 if (newUserInfo
.isRestricted()) {
211 // VPN for a restricted profile is routed through its owner user
212 mVpnUserId
= newUserInfo
.restrictedProfileParentId
;
214 mVpnUserId
= mCurrentUserId
;
219 private String
getNameForVpnConfig(VpnConfig cfg
, UserHandle user
) {
221 return mContext
.getString(R
.string
.legacy_vpn_name
);
223 // The package name for an active VPN is stored in the 'user' field of its VpnConfig
224 final String vpnPackage
= cfg
.user
;
226 Context userContext
= mContext
.createPackageContextAsUser(mContext
.getPackageName(),
227 0 /* flags */, user
);
228 return VpnConfig
.getVpnLabel(userContext
, vpnPackage
).toString();
229 } catch (NameNotFoundException nnfe
) {
230 Log
.e(TAG
, "Package " + vpnPackage
+ " is not present", nnfe
);
235 private void fireCallbacks() {
236 synchronized (mCallbacks
) {
237 for (SecurityControllerCallback callback
: mCallbacks
) {
238 callback
.onStateChanged();
243 private void updateState() {
244 // Find all users with an active VPN
245 SparseArray
<VpnConfig
> vpns
= new SparseArray
<>();
247 for (UserInfo user
: mUserManager
.getUsers()) {
248 VpnConfig cfg
= mConnectivityManagerService
.getVpnConfig(user
.id
);
251 } else if (cfg
.legacy
) {
252 // Legacy VPNs should do nothing if the network is disconnected. Third-party
253 // VPN warnings need to continue as traffic can still go to the app.
254 LegacyVpnInfo legacyVpn
= mConnectivityManagerService
.getLegacyVpnInfo(user
.id
);
255 if (legacyVpn
== null || legacyVpn
.state
!= LegacyVpnInfo
.STATE_CONNECTED
) {
259 vpns
.put(user
.id
, cfg
);
261 } catch (RemoteException rme
) {
262 // Roll back to previous state
263 Log
.e(TAG
, "Unable to list active VPNs", rme
);
269 private String
getPackageNameForVpnConfig(VpnConfig cfg
) {
276 private boolean isVpnPackageBranded(String packageName
) {
279 ApplicationInfo info
= mPackageManager
.getApplicationInfo(packageName
,
280 PackageManager
.GET_META_DATA
);
281 if (info
== null || info
.metaData
== null || !info
.isSystemApp()) {
284 isBranded
= info
.metaData
.getBoolean(VPN_BRANDED_META_DATA
, false);
285 } catch (NameNotFoundException e
) {
291 private final NetworkCallback mNetworkCallback
= new NetworkCallback() {
293 public void onAvailable(Network network
) {
294 if (DEBUG
) Log
.d(TAG
, "onAvailable " + network
.netId
);
299 // TODO Find another way to receive VPN lost. This may be delayed depending on
300 // how long the VPN connection is held on to.
302 public void onLost(Network network
) {
303 if (DEBUG
) Log
.d(TAG
, "onLost " + network
.netId
);