Add a skeleton VpnManagerService, and start it on boot.
This adds a lot of unused code but this should make it easier to review subsequent CLs. Bug: 173331190 Test: builds, boots, "dumpsys vpnmanager" succeeds Change-Id: Ied379654a0c3ab6242d3125661fe30f322395059
This commit is contained in:
24
core/java/android/net/IVpnManager.aidl
Normal file
24
core/java/android/net/IVpnManager.aidl
Normal file
@@ -0,0 +1,24 @@
|
||||
/**
|
||||
* Copyright (c) 2020, 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 android.net;
|
||||
|
||||
/**
|
||||
* Interface that manages VPNs.
|
||||
*/
|
||||
/** {@hide} */
|
||||
interface IVpnManager {
|
||||
}
|
||||
@@ -76,6 +76,12 @@ public class VpnManager {
|
||||
@Deprecated
|
||||
public static final int TYPE_VPN_LEGACY = 3;
|
||||
|
||||
/**
|
||||
* Channel for VPN notifications.
|
||||
* @hide
|
||||
*/
|
||||
public static final String NOTIFICATION_CHANNEL_VPN = "VPN";
|
||||
|
||||
/** @hide */
|
||||
@IntDef(value = {TYPE_VPN_NONE, TYPE_VPN_SERVICE, TYPE_VPN_PLATFORM, TYPE_VPN_LEGACY})
|
||||
@Retention(RetentionPolicy.SOURCE)
|
||||
|
||||
@@ -207,8 +207,5 @@ filegroup {
|
||||
"java/com/android/server/connectivity/QosCallbackAgentConnection.java",
|
||||
"java/com/android/server/connectivity/QosCallbackTracker.java",
|
||||
"java/com/android/server/connectivity/TcpKeepaliveController.java",
|
||||
"java/com/android/server/connectivity/Vpn.java",
|
||||
"java/com/android/server/connectivity/VpnIkev2Utils.java",
|
||||
"java/com/android/server/net/LockdownVpnTracker.java",
|
||||
],
|
||||
}
|
||||
|
||||
199
services/core/java/com/android/server/VpnManagerService.java
Normal file
199
services/core/java/com/android/server/VpnManagerService.java
Normal file
@@ -0,0 +1,199 @@
|
||||
/*
|
||||
* Copyright (C) 2021 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.server;
|
||||
|
||||
import static android.content.pm.PackageManager.PERMISSION_GRANTED;
|
||||
|
||||
import android.annotation.NonNull;
|
||||
import android.annotation.Nullable;
|
||||
import android.content.Context;
|
||||
import android.net.ConnectivityManager;
|
||||
import android.net.INetd;
|
||||
import android.net.IVpnManager;
|
||||
import android.net.NetworkStack;
|
||||
import android.net.util.NetdService;
|
||||
import android.os.Binder;
|
||||
import android.os.Handler;
|
||||
import android.os.HandlerThread;
|
||||
import android.os.INetworkManagementService;
|
||||
import android.os.ServiceManager;
|
||||
import android.os.UserHandle;
|
||||
import android.os.UserManager;
|
||||
import android.security.KeyStore;
|
||||
import android.util.Log;
|
||||
import android.util.SparseArray;
|
||||
|
||||
import com.android.internal.annotations.GuardedBy;
|
||||
import com.android.internal.annotations.VisibleForTesting;
|
||||
import com.android.internal.util.DumpUtils;
|
||||
import com.android.server.connectivity.Vpn;
|
||||
|
||||
import java.io.FileDescriptor;
|
||||
import java.io.PrintWriter;
|
||||
|
||||
/**
|
||||
* Service that tracks and manages VPNs, and backs the VpnService and VpnManager APIs.
|
||||
* @hide
|
||||
*/
|
||||
public class VpnManagerService extends IVpnManager.Stub {
|
||||
private static final String TAG = VpnManagerService.class.getSimpleName();
|
||||
|
||||
@VisibleForTesting
|
||||
protected final HandlerThread mHandlerThread;
|
||||
private final Handler mHandler;
|
||||
|
||||
private final Context mContext;
|
||||
private final Context mUserAllContext;
|
||||
|
||||
|
||||
private final Dependencies mDeps;
|
||||
|
||||
private final ConnectivityManager mCm;
|
||||
private final KeyStore mKeyStore;
|
||||
private final INetworkManagementService mNMS;
|
||||
private final INetd mNetd;
|
||||
private final UserManager mUserManager;
|
||||
|
||||
@VisibleForTesting
|
||||
@GuardedBy("mVpns")
|
||||
protected final SparseArray<Vpn> mVpns = new SparseArray<>();
|
||||
|
||||
/**
|
||||
* Dependencies of VpnManager, for injection in tests.
|
||||
*/
|
||||
@VisibleForTesting
|
||||
public static class Dependencies {
|
||||
/** Returns the calling UID of an IPC. */
|
||||
public int getCallingUid() {
|
||||
return Binder.getCallingUid();
|
||||
}
|
||||
|
||||
/** Creates a HandlerThread to be used by this class. */
|
||||
public HandlerThread makeHandlerThread() {
|
||||
return new HandlerThread("VpnManagerService");
|
||||
}
|
||||
|
||||
/** Returns the KeyStore instance to be used by this class. */
|
||||
public KeyStore getKeyStore() {
|
||||
return KeyStore.getInstance();
|
||||
}
|
||||
|
||||
public INetd getNetd() {
|
||||
return NetdService.getInstance();
|
||||
}
|
||||
|
||||
public INetworkManagementService getINetworkManagementService() {
|
||||
return INetworkManagementService.Stub.asInterface(
|
||||
ServiceManager.getService(Context.NETWORKMANAGEMENT_SERVICE));
|
||||
}
|
||||
}
|
||||
|
||||
public VpnManagerService(Context context, Dependencies deps) {
|
||||
mContext = context;
|
||||
mDeps = deps;
|
||||
mHandlerThread = mDeps.makeHandlerThread();
|
||||
mHandlerThread.start();
|
||||
mHandler = mHandlerThread.getThreadHandler();
|
||||
mKeyStore = mDeps.getKeyStore();
|
||||
mUserAllContext = mContext.createContextAsUser(UserHandle.ALL, 0 /* flags */);
|
||||
mCm = mContext.getSystemService(ConnectivityManager.class);
|
||||
mNMS = mDeps.getINetworkManagementService();
|
||||
mNetd = mDeps.getNetd();
|
||||
mUserManager = mContext.getSystemService(UserManager.class);
|
||||
log("VpnManagerService starting up");
|
||||
}
|
||||
|
||||
/** Creates a new VpnManagerService */
|
||||
public static VpnManagerService create(Context context) {
|
||||
return new VpnManagerService(context, new Dependencies());
|
||||
}
|
||||
|
||||
/** Informs the service that the system is ready. */
|
||||
public void systemReady() {
|
||||
}
|
||||
|
||||
@Override
|
||||
/** Dumps service state. */
|
||||
protected void dump(@NonNull FileDescriptor fd, @NonNull PrintWriter pw,
|
||||
@Nullable String[] args) {
|
||||
if (!DumpUtils.checkDumpPermission(mContext, TAG, pw)) return;
|
||||
}
|
||||
|
||||
private void ensureRunningOnHandlerThread() {
|
||||
if (mHandler.getLooper().getThread() != Thread.currentThread()) {
|
||||
throw new IllegalStateException(
|
||||
"Not running on ConnectivityService thread: "
|
||||
+ Thread.currentThread().getName());
|
||||
}
|
||||
}
|
||||
|
||||
private boolean checkAnyPermissionOf(String... permissions) {
|
||||
for (String permission : permissions) {
|
||||
if (mContext.checkCallingOrSelfPermission(permission) == PERMISSION_GRANTED) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private void enforceAnyPermissionOf(String... permissions) {
|
||||
if (!checkAnyPermissionOf(permissions)) {
|
||||
throw new SecurityException("Requires one of the following permissions: "
|
||||
+ String.join(", ", permissions) + ".");
|
||||
}
|
||||
}
|
||||
|
||||
private void enforceControlAlwaysOnVpnPermission() {
|
||||
mContext.enforceCallingOrSelfPermission(
|
||||
android.Manifest.permission.CONTROL_ALWAYS_ON_VPN,
|
||||
"ConnectivityService");
|
||||
}
|
||||
|
||||
/**
|
||||
* Require that the caller is either in the same user or has appropriate permission to interact
|
||||
* across users.
|
||||
*
|
||||
* @param userId Target user for whatever operation the current IPC is supposed to perform.
|
||||
*/
|
||||
private void enforceCrossUserPermission(int userId) {
|
||||
if (userId == UserHandle.getCallingUserId()) {
|
||||
// Not a cross-user call.
|
||||
return;
|
||||
}
|
||||
mContext.enforceCallingOrSelfPermission(
|
||||
android.Manifest.permission.INTERACT_ACROSS_USERS_FULL,
|
||||
"VpnManagerService");
|
||||
}
|
||||
|
||||
private void enforceSettingsPermission() {
|
||||
enforceAnyPermissionOf(
|
||||
android.Manifest.permission.NETWORK_SETTINGS,
|
||||
NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK);
|
||||
}
|
||||
|
||||
private static void log(String s) {
|
||||
Log.d(TAG, s);
|
||||
}
|
||||
|
||||
private static void logw(String s) {
|
||||
Log.w(TAG, s);
|
||||
}
|
||||
|
||||
private static void loge(String s) {
|
||||
Log.e(TAG, s);
|
||||
}
|
||||
}
|
||||
@@ -79,7 +79,6 @@ public class NetworkNotificationManager {
|
||||
// server.
|
||||
public static final String NOTIFICATION_CHANNEL_NETWORK_STATUS = "NETWORK_STATUS";
|
||||
public static final String NOTIFICATION_CHANNEL_NETWORK_ALERTS = "NETWORK_ALERTS";
|
||||
public static final String NOTIFICATION_CHANNEL_VPN = "VPN";
|
||||
|
||||
// The context is for the current user (system server)
|
||||
private final Context mContext;
|
||||
|
||||
@@ -21,10 +21,10 @@ import static android.net.ConnectivityManager.NETID_UNSET;
|
||||
import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_METERED;
|
||||
import static android.net.RouteInfo.RTN_THROW;
|
||||
import static android.net.RouteInfo.RTN_UNREACHABLE;
|
||||
import static android.net.VpnManager.NOTIFICATION_CHANNEL_VPN;
|
||||
|
||||
import static com.android.internal.util.Preconditions.checkArgument;
|
||||
import static com.android.internal.util.Preconditions.checkNotNull;
|
||||
import static com.android.server.connectivity.NetworkNotificationManager.NOTIFICATION_CHANNEL_VPN;
|
||||
|
||||
import android.Manifest;
|
||||
import android.annotation.NonNull;
|
||||
@@ -172,6 +172,12 @@ public class Vpn {
|
||||
*/
|
||||
@VisibleForTesting static final int MAX_VPN_PROFILE_SIZE_BYTES = 1 << 17; // 128kB
|
||||
|
||||
/**
|
||||
* Network score that VPNs will announce to ConnectivityService.
|
||||
* TODO: remove when the network scoring refactor lands.
|
||||
*/
|
||||
private static final int VPN_DEFAULT_SCORE = 101;
|
||||
|
||||
// TODO: create separate trackers for each unique VPN to support
|
||||
// automated reconnection
|
||||
|
||||
@@ -1233,8 +1239,7 @@ public class Vpn {
|
||||
}
|
||||
|
||||
mNetworkAgent = new NetworkAgent(mContext, mLooper, NETWORKTYPE /* logtag */,
|
||||
mNetworkCapabilities, lp,
|
||||
ConnectivityConstants.VPN_DEFAULT_SCORE, networkAgentConfig, mNetworkProvider) {
|
||||
mNetworkCapabilities, lp, VPN_DEFAULT_SCORE, networkAgentConfig, mNetworkProvider) {
|
||||
@Override
|
||||
public void unwanted() {
|
||||
// We are user controlled, not driven by NetworkRequest.
|
||||
|
||||
@@ -18,9 +18,9 @@ package com.android.server.net;
|
||||
|
||||
import static android.net.ConnectivityManager.TYPE_NONE;
|
||||
import static android.net.NetworkCapabilities.TRANSPORT_VPN;
|
||||
import static android.net.VpnManager.NOTIFICATION_CHANNEL_VPN;
|
||||
import static android.provider.Settings.ACTION_VPN_SETTINGS;
|
||||
|
||||
import static com.android.server.connectivity.NetworkNotificationManager.NOTIFICATION_CHANNEL_VPN;
|
||||
|
||||
import android.annotation.NonNull;
|
||||
import android.annotation.Nullable;
|
||||
|
||||
@@ -1104,6 +1104,7 @@ public final class SystemServer {
|
||||
IStorageManager storageManager = null;
|
||||
NetworkManagementService networkManagement = null;
|
||||
IpSecService ipSecService = null;
|
||||
VpnManagerService vpnManager = null;
|
||||
VcnManagementService vcnManagement = null;
|
||||
NetworkStatsService networkStats = null;
|
||||
NetworkPolicyManagerService networkPolicy = null;
|
||||
@@ -1637,6 +1638,15 @@ public final class SystemServer {
|
||||
networkPolicy.bindConnectivityManager(connectivity);
|
||||
t.traceEnd();
|
||||
|
||||
t.traceBegin("StartVpnManagerService");
|
||||
try {
|
||||
vpnManager = VpnManagerService.create(context);
|
||||
ServiceManager.addService(Context.VPN_MANAGEMENT_SERVICE, vpnManager);
|
||||
} catch (Throwable e) {
|
||||
reportWtf("starting VPN Manager Service", e);
|
||||
}
|
||||
t.traceEnd();
|
||||
|
||||
t.traceBegin("StartVcnManagementService");
|
||||
try {
|
||||
vcnManagement = VcnManagementService.create(context);
|
||||
@@ -2338,6 +2348,7 @@ public final class SystemServer {
|
||||
final MediaRouterService mediaRouterF = mediaRouter;
|
||||
final MmsServiceBroker mmsServiceF = mmsService;
|
||||
final IpSecService ipSecServiceF = ipSecService;
|
||||
final VpnManagerService vpnManagerF = vpnManager;
|
||||
final VcnManagementService vcnManagementF = vcnManagement;
|
||||
final WindowManagerService windowManagerF = wm;
|
||||
final ConnectivityManager connectivityF = (ConnectivityManager)
|
||||
@@ -2445,6 +2456,15 @@ public final class SystemServer {
|
||||
reportWtf("making Connectivity Service ready", e);
|
||||
}
|
||||
t.traceEnd();
|
||||
t.traceBegin("MakeVpnManagerServiceReady");
|
||||
try {
|
||||
if (vpnManagerF != null) {
|
||||
vpnManagerF.systemReady();
|
||||
}
|
||||
} catch (Throwable e) {
|
||||
reportWtf("making VpnManagerService ready", e);
|
||||
}
|
||||
t.traceEnd();
|
||||
t.traceBegin("MakeVcnManagementServiceReady");
|
||||
try {
|
||||
if (vcnManagementF != null) {
|
||||
|
||||
Reference in New Issue
Block a user